extern crate libc;
use exception::{
self, Exception, ABORT, CONTROL_STRUCTURE_MISMATCH, DIVISION_BY_ZERO,
FLOATING_POINT_STACK_OVERFLOW, FLOATING_POINT_STACK_UNDERFLOW,
INTERPRETING_A_COMPILE_ONLY_WORD, INVALID_MEMORY_ADDRESS, INVALID_NUMERIC_ARGUMENT,
RETURN_STACK_OVERFLOW, RETURN_STACK_UNDERFLOW, STACK_OVERFLOW, STACK_UNDERFLOW, UNDEFINED_WORD,
UNEXPECTED_END_OF_FILE, UNSUPPORTED_OPERATION,
};
use hibitset::{BitSet, BitSetLike};
use loader::Source;
use memory::{DataSpace, Memory};
use parser;
use std::fmt::Write;
use std::fmt::{self, Display};
use std::fs::File;
use std::mem;
use std::ops::{Index, IndexMut};
use std::str;
use {FALSE, NUM_TASKS, TRUE};
pub struct Word<Target> {
is_immediate: bool,
is_compile_only: bool,
hidden: bool,
link: usize,
hash: u32,
nfa: usize,
dfa: usize,
doer: usize,
action: fn(&mut Target),
pub(crate) compilation_semantics: fn(&mut Target, usize),
pub(crate) min_execution_time: usize,
pub(crate) max_execution_time: usize,
}
impl<Target> Word<Target> {
pub fn new(
action: fn(&mut Target),
compilation_semantics: fn(&mut Target, usize),
nfa: usize,
dfa: usize,
) -> Word<Target> {
Word {
is_immediate: false,
is_compile_only: false,
hidden: false,
link: 0,
hash: 0,
nfa: nfa,
dfa: dfa,
doer: 0,
action: action,
compilation_semantics: compilation_semantics,
min_execution_time: 0,
max_execution_time: 0,
}
}
pub fn is_immediate(&self) -> bool {
self.is_immediate
}
pub fn set_immediate(&mut self, flag: bool) {
self.is_immediate = flag;
}
pub fn is_compile_only(&self) -> bool {
self.is_compile_only
}
pub fn set_compile_only(&mut self, flag: bool) {
self.is_compile_only = flag;
}
pub fn is_hidden(&self) -> bool {
self.hidden
}
pub fn set_hidden(&mut self, flag: bool) {
self.hidden = flag;
}
pub fn nfa(&self) -> usize {
self.nfa
}
pub fn dfa(&self) -> usize {
self.dfa
}
pub fn action(&self) -> fn(&mut Target) {
self.action
}
}
const BUCKET_SIZE: usize = 64;
pub struct Wordlist<Target> {
words: Vec<Word<Target>>,
buckets: [usize; BUCKET_SIZE],
temp_buckets: [usize; BUCKET_SIZE],
last: usize,
}
impl<Target> Wordlist<Target> {
pub fn with_capacity(cap: usize) -> Wordlist<Target> {
Wordlist {
words: Vec::with_capacity(cap),
buckets: [0; BUCKET_SIZE],
temp_buckets: [0; BUCKET_SIZE],
last: 0,
}
}
pub fn len(&self) -> usize {
self.words.len()
}
fn hash(name: &str) -> u32 {
let mut hash: u32 = 5381;
for c in name.bytes() {
hash = hash
.wrapping_shl(5)
.wrapping_add(hash)
.wrapping_add(c.to_ascii_lowercase() as u32);
}
hash
}
fn push(&mut self, name: &str, mut w: Word<Target>) {
w.hash = Self::hash(name);
let b = w.hash as usize % BUCKET_SIZE;
w.link = self.buckets[b];
self.last = self.words.len();
self.buckets[b] = self.last;
self.words.push(w);
}
fn truncate(&mut self, i: usize) {
self.words.truncate(i);
self.last = self.words.len() - 1;
}
pub fn find_xt(&self, addr: usize) -> Option<usize> {
let result = self.words.binary_search_by(|w| w.nfa().cmp(&addr));
match result {
Ok(xt) => Some(xt),
Err(xt) => {
if xt == 0 {
None
} else {
Some(xt - 1)
}
}
}
}
}
impl<Target> Index<usize> for Wordlist<Target> {
type Output = Word<Target>;
#[inline(always)]
fn index(&self, index: usize) -> &Word<Target> {
&self.words[index]
}
}
impl<Target> IndexMut<usize> for Wordlist<Target> {
#[inline(always)]
fn index_mut(&mut self, index: usize) -> &mut Word<Target> {
&mut self.words[index]
}
}
pub struct Stack<T: Default> {
pub inner: [T; 256],
pub len: u8,
pub canary: T,
}
impl<T: Default + Copy + PartialEq + Display> Stack<T> {
pub fn new(canary: T) -> Self {
let mut result = Stack {
inner: [T::default(); 256],
len: 0,
canary: canary,
};
result.reset();
result
}
pub fn reset(&mut self) {
self.len = 0;
for i in 0..256 {
self.inner[i] = self.canary;
}
}
pub fn underflow(&self) -> bool {
(self.inner[255] != self.canary) || (self.len > 128)
}
pub fn overflow(&self) -> bool {
(self.inner[64] != self.canary) || (self.len > 64 && self.len <= 128)
}
pub fn push(&mut self, v: T) {
let len = self.len.wrapping_add(1);
self.len = len;
self.inner[len.wrapping_sub(1) as usize] = v;
}
pub fn pop(&mut self) -> T {
let result = self.inner[self.len.wrapping_sub(1) as usize];
self.len = self.len.wrapping_sub(1);
result
}
pub fn push2(&mut self, v1: T, v2: T) {
let len = self.len.wrapping_add(2);
self.len = len;
self.inner[self.len.wrapping_sub(2) as usize] = v1;
self.inner[self.len.wrapping_sub(1) as usize] = v2;
}
pub fn push3(&mut self, v1: T, v2: T, v3: T) {
let len = self.len.wrapping_add(3);
self.len = len;
self.inner[self.len.wrapping_sub(3) as usize] = v1;
self.inner[self.len.wrapping_sub(2) as usize] = v2;
self.inner[self.len.wrapping_sub(1) as usize] = v3;
}
pub fn pop2(&mut self) -> (T, T) {
let result = (
self.inner[self.len.wrapping_sub(2) as usize],
self.inner[self.len.wrapping_sub(1) as usize],
);
self.len = self.len.wrapping_sub(2);
result
}
pub fn pop3(&mut self) -> (T, T, T) {
let result = (
self.inner[self.len.wrapping_sub(3) as usize],
self.inner[self.len.wrapping_sub(2) as usize],
self.inner[self.len.wrapping_sub(1) as usize],
);
self.len = self.len.wrapping_sub(3);
result
}
pub fn last(&self) -> Option<T> {
Some(self.inner[self.len.wrapping_sub(1) as usize])
}
pub fn get(&self, pos: u8) -> Option<T> {
Some(self.inner[pos as usize])
}
pub fn len(&self) -> u8 {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn as_slice(&self) -> &[T] {
&self.inner[..self.len as usize]
}
}
impl Index<u8> for Stack<isize> {
type Output = isize;
#[inline(always)]
fn index(&self, index: u8) -> &isize {
&self.inner[index as usize]
}
}
impl IndexMut<u8> for Stack<isize> {
#[inline(always)]
fn index_mut(&mut self, index: u8) -> &mut isize {
&mut self.inner[index as usize]
}
}
impl Index<u8> for Stack<f64> {
type Output = f64;
#[inline(always)]
fn index(&self, index: u8) -> &f64 {
&self.inner[index as usize]
}
}
impl IndexMut<u8> for Stack<f64> {
#[inline(always)]
fn index_mut(&mut self, index: u8) -> &mut f64 {
&mut self.inner[index as usize]
}
}
impl Index<u8> for Stack<Control> {
type Output = Control;
#[inline(always)]
fn index(&self, index: u8) -> &Control {
&self.inner[index as usize]
}
}
impl fmt::Debug for Stack<isize> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.len == 0 {
} else {
for i in 0..self.len {
let v = self[i];
match write!(f, "{} ", v) {
Ok(_) => {}
Err(e) => {
return Err(e);
}
}
}
}
Ok(())
}
}
impl fmt::Debug for Stack<f64> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.len == 0 {
} else {
for i in 0..self.len {
let v = self[i];
match write!(f, "{:.7} ", v) {
Ok(_) => {}
Err(e) => {
return Err(e);
}
}
}
}
Ok(())
}
}
#[allow(non_snake_case)]
pub struct ForwardReferences {
pub idx_lit: usize,
pub idx_flit: usize,
pub idx_exit: usize,
pub idx_zero_branch: usize,
pub idx_branch: usize,
pub idx_do: usize,
pub idx_qdo: usize,
pub idx_loop: usize,
pub idx_plus_loop: usize,
pub idx_s_quote: usize,
pub idx_type: usize,
pub idx_over: usize,
pub idx_equal: usize,
pub idx_drop: usize,
pub idx__postpone: usize,
pub idx_to_r: usize,
pub idx__does: usize,
}
impl ForwardReferences {
pub fn new() -> ForwardReferences {
ForwardReferences {
idx_lit: 0,
idx_flit: 0,
idx_exit: 0,
idx_zero_branch: 0,
idx_branch: 0,
idx_do: 0,
idx_qdo: 0,
idx_loop: 0,
idx_plus_loop: 0,
idx_s_quote: 0,
idx_type: 0,
idx_over: 0,
idx_equal: 0,
idx_drop: 0,
idx__postpone: 0,
idx_to_r: 0,
idx__does: 0,
}
}
}
pub struct State {
pub is_compiling: bool,
pub instruction_pointer: usize,
word_pointer: usize,
pub aborted_word_pointer: usize,
pub source_index: usize,
pub source_id: isize,
}
impl State {
pub fn new() -> State {
State {
is_compiling: false,
instruction_pointer: 0,
word_pointer: 0,
aborted_word_pointer: 0,
source_index: 0,
source_id: 0,
}
}
pub fn word_pointer(&self) -> usize {
self.word_pointer
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum Control {
Default,
Canary,
If(usize),
Else(usize),
Begin(usize),
While(usize),
Do(usize, usize),
Case,
Of(usize),
Endof(usize),
}
impl Default for Control {
fn default() -> Self {
Control::Default
}
}
impl Display for Control {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match *self {
Control::Default => "Default",
Control::Canary => "Canary",
Control::If(_) => "If",
Control::Else(_) => "Else",
Control::Begin(_) => "Begin",
Control::While(_) => "While",
Control::Do(_, _) => "Do",
Control::Case => "Case",
Control::Of(_) => "Of",
Control::Endof(_) => "Endof",
};
write!(f, "{}", s)
}
}
pub trait Core: Sized {
fn last_error(&self) -> Option<Exception>;
fn set_error(&mut self, e: Option<Exception>);
fn handler(&self) -> usize;
fn set_handler(&mut self, h: usize);
fn data_space(&mut self) -> &mut DataSpace;
fn data_space_const(&self) -> &DataSpace;
fn hold_buffer(&mut self) -> &mut String;
fn output_buffer(&mut self) -> &mut Option<String>;
fn set_output_buffer(&mut self, buffer: String);
fn source_id(&self) -> isize;
fn input_buffer(&mut self) -> &mut Option<String>;
fn set_input_buffer(&mut self, buffer: String);
fn files(&self) -> &Vec<Option<File>>;
fn files_mut(&mut self) -> &mut Vec<Option<File>>;
fn sources(&self) -> &Vec<Option<Source>>;
fn sources_mut(&mut self) -> &mut Vec<Option<Source>>;
fn lines(&self) -> &Vec<Option<String>>;
fn lines_mut(&mut self) -> &mut Vec<Option<String>>;
fn last_token(&mut self) -> &mut Option<String>;
fn set_last_token(&mut self, buffer: String);
fn s_stack(&mut self) -> &mut Stack<isize>;
fn r_stack(&mut self) -> &mut Stack<isize>;
fn c_stack(&mut self) -> &mut Stack<Control>;
fn f_stack(&mut self) -> &mut Stack<f64>;
fn wordlist_mut(&mut self) -> &mut Wordlist<Self>;
fn wordlist(&self) -> &Wordlist<Self>;
fn state(&mut self) -> &mut State;
fn references(&mut self) -> &mut ForwardReferences;
fn system_time_ns(&self) -> u64;
fn current_task(&self) -> usize;
fn set_current_task(&mut self, i: usize);
fn awake(&self, i: usize) -> bool;
fn set_awake(&mut self, i: usize, v: bool);
fn forward_bitset(&self) -> &BitSet;
fn forward_bitset_mut(&mut self) -> &mut BitSet;
fn resolved_bitset(&self) -> &BitSet;
fn resolved_bitset_mut(&mut self) -> &mut BitSet;
fn labels(&self) -> &Vec<usize>;
fn labels_mut(&mut self) -> &mut Vec<usize>;
fn add_core(&mut self) {
self.add_primitive("", Core::noop);
self.add_primitive("noop", Core::noop);
self.add_compile_only("exit", Core::exit);
self.add_compile_only("lit", Core::lit);
self.add_compile_only("flit", Core::flit);
self.add_compile_only("_s\"", Core::p_s_quote);
self.add_compile_only("branch", Core::branch);
self.add_compile_only("0branch", Core::zero_branch);
self.add_compile_only("_do", Core::_do);
self.add_compile_only("_qdo", Core::_qdo);
self.add_compile_only("_loop", Core::_loop);
self.add_compile_only("_+loop", Core::_plus_loop);
self.add_compile_only("unloop", Core::unloop);
self.add_compile_only("leave", Core::leave);
self.add_compile_only("i", Core::p_i);
self.add_compile_only("j", Core::p_j);
self.add_compile_only(">r", Core::p_to_r);
self.add_compile_only("r>", Core::r_from);
self.add_compile_only("r@", Core::r_fetch);
self.add_compile_only("2>r", Core::two_to_r);
self.add_compile_only("2r>", Core::two_r_from);
self.add_compile_only("2r@", Core::two_r_fetch);
self.add_compile_only("compile,", Core::compile_comma);
self.add_compile_only("_postpone", Core::_postpone);
self.add_compile_only("_does", Core::_does);
self.add_primitive("execute", Core::execute);
self.add_primitive("dup", Core::dup);
self.add_primitive("drop", Core::p_drop);
self.add_primitive("swap", Core::swap);
self.add_primitive("over", Core::over);
self.add_primitive("nip", Core::nip);
self.add_primitive("depth", Core::depth);
self.add_primitive("?stacks", Core::check_stacks);
self.add_primitive("0<", Core::zero_less);
self.add_primitive("=", Core::equals);
self.add_primitive("<", Core::less_than);
self.add_primitive("invert", Core::invert);
self.add_primitive("and", Core::and);
self.add_primitive("or", Core::or);
self.add_primitive("xor", Core::xor);
self.add_primitive("lshift", Core::lshift);
self.add_primitive("rshift", Core::rshift);
self.add_primitive("1+", Core::one_plus);
self.add_primitive("1-", Core::one_minus);
self.add_primitive("-", Core::minus);
self.add_primitive("+", Core::plus);
self.add_primitive("*", Core::star);
self.add_primitive("/mod", Core::slash_mod);
self.add_primitive("cell+", Core::cell_plus);
self.add_primitive("cells", Core::cells);
self.add_primitive("@", Core::fetch);
self.add_primitive("!", Core::store);
self.add_primitive("char+", Core::char_plus);
self.add_primitive("here", Core::here);
self.add_primitive("allot", Core::allot);
self.add_primitive("aligned", Core::aligned);
self.add_primitive("align", Core::align);
self.add_primitive("c@", Core::c_fetch);
self.add_primitive("c!", Core::c_store);
self.add_primitive("move", Core::p_move);
self.add_primitive("base", Core::base);
self.add_primitive("immediate", Core::immediate);
self.add_primitive("compile-only", Core::compile_only);
self.add_immediate("(", Core::imm_paren);
self.add_immediate("\\", Core::imm_backslash);
self.add_immediate("[", Core::left_bracket);
self.add_immediate_and_compile_only("[']", Core::bracket_tick);
self.add_immediate_and_compile_only("[char]", Core::bracket_char);
self.add_immediate_and_compile_only(";", Core::semicolon);
self.add_immediate_and_compile_only("if", Core::imm_if);
self.add_immediate_and_compile_only("else", Core::imm_else);
self.add_immediate_and_compile_only("then", Core::imm_then);
self.add_immediate_and_compile_only("case", Core::imm_case);
self.add_immediate_and_compile_only("of", Core::imm_of);
self.add_immediate_and_compile_only("endof", Core::imm_endof);
self.add_immediate_and_compile_only("endcase", Core::imm_endcase);
self.add_immediate_and_compile_only("begin", Core::imm_begin);
self.add_immediate_and_compile_only("while", Core::imm_while);
self.add_immediate_and_compile_only("repeat", Core::imm_repeat);
self.add_immediate_and_compile_only("until", Core::imm_until);
self.add_immediate_and_compile_only("again", Core::imm_again);
self.add_immediate("0labels", Core::imm_clear_labels);
self.add_immediate_and_compile_only("label", Core::imm_label);
self.add_immediate_and_compile_only("goto", Core::imm_goto);
self.add_immediate_and_compile_only("call", Core::imm_call);
self.add_immediate_and_compile_only("recurse", Core::imm_recurse);
self.add_immediate_and_compile_only("do", Core::imm_do);
self.add_immediate_and_compile_only("?do", Core::imm_qdo);
self.add_immediate_and_compile_only("loop", Core::imm_loop);
self.add_immediate_and_compile_only("+loop", Core::imm_plus_loop);
self.add_immediate_and_compile_only("postpone", Core::postpone);
self.add_immediate_and_compile_only("does>", Core::does);
self.add_primitive("true", Core::p_true);
self.add_primitive("false", Core::p_false);
self.add_primitive("not", Core::zero_equals);
self.add_primitive("0=", Core::zero_equals);
self.add_primitive("0>", Core::zero_greater);
self.add_primitive("0<>", Core::zero_not_equals);
self.add_primitive(">", Core::greater_than);
self.add_primitive("<>", Core::not_equals);
self.add_primitive("within", Core::within);
self.add_primitive("rot", Core::rot);
self.add_primitive("-rot", Core::minus_rot);
self.add_primitive("pick", Core::pick);
self.add_primitive("2dup", Core::two_dup);
self.add_primitive("2drop", Core::two_drop);
self.add_primitive("2swap", Core::two_swap);
self.add_primitive("2over", Core::two_over);
self.add_primitive("/", Core::slash);
self.add_primitive("mod", Core::p_mod);
self.add_primitive("abs", Core::abs);
self.add_primitive("negate", Core::negate);
self.add_primitive("parse-word", Core::parse_word);
self.add_primitive("char", Core::char);
self.add_primitive("_skip", Core::_skip);
self.add_primitive("parse", Core::parse);
self.add_primitive(":", Core::colon);
self.add_primitive("constant", Core::constant);
self.add_primitive("create", Core::create);
self.add_primitive("'", Core::tick);
self.add_primitive(">body", Core::to_body);
self.add_primitive(">name", Core::to_name);
self.add_primitive("]", Core::right_bracket);
self.add_primitive(",", Core::comma);
self.add_primitive("marker", Core::marker);
self.add_primitive("handler!", Core::handler_store);
self.add_primitive("error", Core::error);
self.add_primitive(".error", Core::dot_error);
self.add_primitive("0error", Core::clear_error);
self.add_primitive("0stacks", Core::clear_stacks);
self.add_primitive("reset", Core::reset);
self.add_primitive("abort", Core::abort);
self.add_primitive("compiling?", Core::p_compiling);
self.add_primitive("token-empty?", Core::token_empty);
self.add_primitive(".token", Core::dot_token);
self.add_primitive("!token", Core::store_token);
self.add_primitive("compile-token", Core::compile_token);
self.add_primitive("interpret-token", Core::interpret_token);
self.add_primitive("source-id", Core::p_source_id);
self.add_primitive("source-id!", Core::p_set_source_id);
self.add_primitive("source-idx", Core::p_source_idx);
self.add_primitive("source-idx!", Core::p_set_source_idx);
self.add_primitive("bye", Core::bye);
self.references().idx_lit = self.find("lit").expect("lit undefined");
self.references().idx_flit = self.find("flit").expect("flit undefined");
self.references().idx_exit = self.find("exit").expect("exit undefined");
self.references().idx_zero_branch = self.find("0branch").expect("0branch undefined");
self.references().idx_branch = self.find("branch").expect("branch undefined");
self.references().idx_do = self.find("_do").expect("_do undefined");
self.references().idx_qdo = self.find("_qdo").expect("_qdo undefined");
self.references().idx_loop = self.find("_loop").expect("_loop undefined");
self.references().idx_plus_loop = self.find("_+loop").expect("_+loop undefined");
self.references().idx_over = self.find("over").expect("over undefined");
self.references().idx_equal = self.find("=").expect("= undefined");
self.references().idx_drop = self.find("drop").expect("drop undefined");
self.references().idx__postpone = self.find("_postpone").expect("_postpone undefined");
self.references().idx_to_r = self.find(">r").expect(">r");
self.references().idx__does = self.find("_does").expect("_does");
self.patch_compilation_semanticses();
{
self.add_compile_only("pause", Core::pause);
self.add_compile_only("activate", Core::activate);
self.add_primitive("me", Core::me);
self.add_primitive("suspend", Core::suspend);
self.add_primitive("resume", Core::resume);
}
self.set_awake(0, true);
}
fn add_primitive(&mut self, name: &str, action: fn(&mut Self)) {
let nfa = self.data_space().compile_str(name);
self.data_space().align();
let word = Word::new(action, Core::compile_word, nfa, self.data_space().here());
self.wordlist_mut().push(name, word);
}
fn immediate(&mut self) {
let def = self.wordlist().last;
self.wordlist_mut()[def].set_immediate(true);
}
fn add_immediate(&mut self, name: &str, action: fn(&mut Self)) {
self.add_primitive(name, action);
self.immediate();
}
fn compile_only(&mut self) {
let def = self.wordlist().last;
self.wordlist_mut()[def].set_compile_only(true);
}
fn add_compile_only(&mut self, name: &str, action: fn(&mut Self)) {
self.add_primitive(name, action);
self.compile_only();
}
fn add_immediate_and_compile_only(&mut self, name: &str, action: fn(&mut Self)) {
self.add_primitive(name, action);
self.immediate();
self.compile_only();
}
fn execute_word(&mut self, i: usize) {
self.state().word_pointer = i;
if i < self.wordlist().len() {
(self.wordlist()[i].action())(self);
} else {
self.abort_with(UNSUPPORTED_OPERATION);
}
}
fn find(&mut self, name: &str) -> Option<usize> {
let hash = Wordlist::<Self>::hash(name);
let mut w = self.wordlist().buckets[hash as usize % BUCKET_SIZE];
while w != 0 {
if !self.wordlist()[w].is_hidden() {
{
if self.wordlist()[w].hash == hash {
let nfa = self.wordlist()[w].nfa();
let w_name = unsafe { self.data_space().get_str(nfa) };
if w_name.eq_ignore_ascii_case(name) {
return Some(w);
}
}
}
}
w = self.wordlist()[w].link;
}
None
}
#[inline(never)]
fn run(&mut self) {
let mut ip = self.state().instruction_pointer;
while self.data_space().start() <= ip
&& ip + mem::size_of::<isize>() <= self.data_space().limit()
{
let w = unsafe { self.data_space().get_isize(ip) as usize };
self.state().instruction_pointer += mem::size_of::<isize>();
self.execute_word(w);
ip = self.state().instruction_pointer;
}
}
fn forth(&mut self) -> bool {
let mut ip = self.state().instruction_pointer;
if self.data_space().start() <= ip
&& ip + mem::size_of::<isize>() <= self.data_space().limit()
{
let w = unsafe { self.data_space().get_isize(ip) as usize };
self.state().instruction_pointer += mem::size_of::<isize>();
self.execute_word(w);
ip = self.state().instruction_pointer;
true
} else {
false
}
}
fn compile_word(&mut self, word_index: usize) {
self.data_space().compile_usize(word_index as usize);
}
fn compile_nest(&mut self, word_index: usize) {
self.compile_word(word_index);
}
fn compile_nest_code(&mut self, _: usize) {
}
fn compile_var(&mut self, word_index: usize) {
self.compile_word(word_index);
}
fn compile_const(&mut self, word_index: usize) {
self.compile_word(word_index);
}
fn compile_unmark(&mut self, word_index: usize) {
self.compile_word(word_index);
}
fn compile_fconst(&mut self, word_index: usize) {
self.compile_word(word_index);
}
fn lit(&mut self) {
let ip = self.state().instruction_pointer;
let v = unsafe { self.data_space().get_isize(ip) as isize };
let slen = self.s_stack().len.wrapping_add(1);
self.s_stack().len = slen;
self.s_stack()[slen.wrapping_sub(1)] = v;
self.state().instruction_pointer += mem::size_of::<isize>();
}
fn compile_integer(&mut self, i: isize) {
let idx = self.references().idx_lit;
self.compile_word(idx);
self.data_space().compile_isize(i as isize);
}
fn flit(&mut self) {
let ip = DataSpace::aligned_f64(self.state().instruction_pointer as usize);
let v = unsafe { self.data_space().get_f64(ip) };
let flen = self.f_stack().len.wrapping_add(1);
self.f_stack().len = flen;
self.f_stack()[flen.wrapping_sub(1)] = v;
self.state().instruction_pointer = ip + mem::size_of::<f64>();
}
fn compile_float(&mut self, f: f64) {
let idx_flit = self.references().idx_flit;
self.compile_word(idx_flit);
self.data_space().align_f64();
self.data_space().compile_f64(f);
}
fn p_s_quote(&mut self) {
let ip = self.state().instruction_pointer;
let (addr, cnt) = {
let s = unsafe { self.data_space().get_str(ip) };
(s.as_ptr() as isize, s.len() as isize)
};
let slen = self.s_stack().len.wrapping_add(2);
self.s_stack().len = slen;
self.s_stack()[slen.wrapping_sub(1)] = cnt;
self.s_stack()[slen.wrapping_sub(2)] = addr;
self.state().instruction_pointer = DataSpace::aligned(
self.state().instruction_pointer + mem::size_of::<isize>() + cnt as usize,
);
}
fn patch_compilation_semanticses(&mut self) {
let idx_leave = self.find("leave").expect("leave");
self.wordlist_mut()[idx_leave].compilation_semantics = Self::compile_leave;
}
fn branch(&mut self) {
let ip = self.state().instruction_pointer;
self.state().instruction_pointer = unsafe { self.data_space().get_isize(ip) as usize };
}
fn compile_branch(&mut self, destination: usize) -> usize {
let idx = self.references().idx_branch;
self.compile_word(idx);
self.data_space().compile_isize(destination as isize);
self.data_space().here()
}
fn zero_branch(&mut self) {
let v = self.s_stack().pop();
if v == 0 {
self.branch();
} else {
self.state().instruction_pointer += mem::size_of::<isize>();
}
}
fn compile_zero_branch(&mut self, destination: usize) -> usize {
let idx = self.references().idx_zero_branch;
self.compile_word(idx);
self.data_space().compile_isize(destination as isize);
self.data_space().here()
}
fn _do(&mut self) {
let ip = self.state().instruction_pointer as isize;
self.r_stack().push(ip);
self.state().instruction_pointer += mem::size_of::<isize>();
let (n, t) = self.s_stack().pop2();
let rt = isize::min_value().wrapping_add(t).wrapping_sub(n);
let rn = t.wrapping_sub(rt);
self.r_stack().push2(rn, rt);
}
fn _qdo(&mut self) {
let (n, t) = self.s_stack().pop2();
if n == t {
self.branch();
} else {
let ip = self.state().instruction_pointer as isize;
self.r_stack().push(ip);
self.state().instruction_pointer += mem::size_of::<isize>();
let rt = isize::min_value().wrapping_add(t).wrapping_sub(n);
let rn = t.wrapping_sub(rt);
self.r_stack().push2(rn, rt);
}
}
fn _loop(&mut self) {
let rt = self.r_stack().pop();
match rt.checked_add(1) {
Some(sum) => {
self.r_stack().push(sum);
self.branch();
}
None => {
let _ = self.r_stack().pop2();
self.state().instruction_pointer += mem::size_of::<isize>();
}
}
}
fn _plus_loop(&mut self) {
let rt = self.r_stack().pop();
let t = self.s_stack().pop();
match rt.checked_add(t) {
Some(sum) => {
self.r_stack().push(sum);
self.branch();
}
None => {
let _ = self.r_stack().pop2();
self.state().instruction_pointer += mem::size_of::<isize>();
}
}
}
fn unloop(&mut self) {
let _ = self.r_stack().pop3();
}
fn leave(&mut self) {
let (third, _, _) = self.r_stack().pop3();
if self.r_stack().underflow() {
self.abort_with(RETURN_STACK_UNDERFLOW);
return;
}
self.state().instruction_pointer =
unsafe { self.data_space().get_isize(third as usize) as usize };
}
fn compile_leave(&mut self, word_idx: usize) {
match self.leave_part() {
Some(leave_part) => {
self.compile_word(word_idx);
}
_ => {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
return;
}
};
}
fn p_j(&mut self) {
let pos = self.r_stack().len() - 4;
match self.r_stack().get(pos) {
Some(jt) => match self.r_stack().get(pos - 1) {
Some(jn) => {
self.s_stack().push(jt.wrapping_add(jn));
}
None => self.abort_with(RETURN_STACK_UNDERFLOW),
},
None => self.abort_with(RETURN_STACK_UNDERFLOW),
}
}
fn leave_part(&mut self) -> Option<usize> {
let position = self.c_stack().as_slice().iter().rposition(|&c| match c {
Control::Do(_, _) => true,
_ => false,
});
match position {
Some(p) => match self.c_stack()[p as u8] {
Control::Do(_, leave_part) => Some(leave_part),
_ => None,
},
_ => None,
}
}
fn imm_if(&mut self) {
let here = self.compile_zero_branch(0);
self.c_stack().push(Control::If(here));
}
fn imm_else(&mut self) {
let if_part = match self.c_stack().pop() {
Control::If(if_part) => if_part,
_ => {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
return;
}
};
if self.c_stack().underflow() {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
} else {
let here = self.compile_branch(0);
self.c_stack().push(Control::Else(here));
unsafe {
self.data_space()
.put_isize(here as isize, if_part - mem::size_of::<isize>());
}
}
}
fn imm_then(&mut self) {
let branch_part = match self.c_stack().pop() {
Control::If(branch_part) => branch_part,
Control::Else(branch_part) => branch_part,
_ => {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
return;
}
};
if self.c_stack().underflow() {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
} else {
let here = self.data_space().here();
unsafe {
self.data_space()
.put_isize(here as isize, branch_part - mem::size_of::<isize>());
}
}
}
fn imm_case(&mut self) {
self.c_stack().push(Control::Case);
}
fn imm_of(&mut self) {
match self.c_stack().pop() {
Control::Case => {
self.c_stack().push(Control::Case);
}
Control::Endof(n) => {
self.c_stack().push(Control::Endof(n));
}
_ => {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
return;
}
};
if self.c_stack().underflow() {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
} else {
let idx = self.references().idx_over;
self.compile_word(idx);
let idx = self.references().idx_equal;
self.compile_word(idx);
let here = self.compile_zero_branch(0);
self.c_stack().push(Control::Of(here));
let idx = self.references().idx_drop;
self.compile_word(idx);
}
}
fn imm_endof(&mut self) {
let of_part = match self.c_stack().pop() {
Control::Of(of_part) => of_part,
_ => {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
return;
}
};
if self.c_stack().underflow() {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
} else {
let here = self.compile_branch(0);
self.c_stack().push(Control::Endof(here));
unsafe {
self.data_space()
.put_isize(here as isize, of_part - mem::size_of::<isize>());
}
}
}
fn imm_endcase(&mut self) {
let idx = self.references().idx_drop;
self.compile_word(idx);
loop {
let endof_part = match self.c_stack().pop() {
Control::Case => {
break;
}
Control::Endof(endof_part) => endof_part,
_ => {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
return;
}
};
if self.c_stack().underflow() {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
} else {
let here = self.data_space().here();
unsafe {
self.data_space()
.put_isize(here as isize, endof_part - mem::size_of::<isize>());
}
}
}
if self.c_stack().underflow() {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
}
}
fn imm_begin(&mut self) {
let here = self.data_space().here();
self.c_stack().push(Control::Begin(here));
}
fn imm_while(&mut self) {
let here = self.compile_zero_branch(0);
self.c_stack().push(Control::While(here));
}
fn imm_repeat(&mut self) {
let (begin_part, while_part) = match self.c_stack().pop2() {
(Control::Begin(begin_part), Control::While(while_part)) => (begin_part, while_part),
_ => {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
return;
}
};
if self.c_stack().underflow() {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
} else {
let here = self.compile_branch(begin_part);
unsafe {
self.data_space()
.put_isize(here as isize, while_part - mem::size_of::<isize>());
}
}
}
fn imm_until(&mut self) {
let begin_part = match self.c_stack().pop() {
Control::Begin(begin_part) => begin_part,
_ => {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
return;
}
};
if self.c_stack().underflow() {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
} else {
self.compile_zero_branch(begin_part);
}
}
fn imm_again(&mut self) {
let begin_part = match self.c_stack().pop() {
Control::Begin(begin_part) => begin_part,
_ => {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
return;
}
};
if self.c_stack().underflow() {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
} else {
self.compile_branch(begin_part);
}
}
fn imm_clear_labels(&mut self) {
self.forward_bitset_mut().clear();
self.resolved_bitset_mut().clear();
}
fn imm_label(&mut self) {
let n = self.s_stack().pop() as usize;
if 0 < n && n < self.labels().capacity() {
let here = self.data_space().here();
if self.forward_bitset().contains(n as u32) {
let mut p = self.labels()[n];
loop {
let last = unsafe { self.data_space().get_usize(p) };
unsafe {
self.data_space().put_isize(here as isize, p as usize);
}
if last == 0 {
break;
}
p = last;
}
self.labels_mut()[n] = here;
self.forward_bitset_mut().remove(n as u32);
self.resolved_bitset_mut().add(n as u32);
} else if self.resolved_bitset().contains(n as u32) {
self.abort_with(INVALID_NUMERIC_ARGUMENT);
} else {
self.labels_mut()[n] = here;
self.resolved_bitset_mut().add(n as u32);
}
} else {
self.abort_with(INVALID_NUMERIC_ARGUMENT);
}
}
fn imm_goto(&mut self) {
let n = self.s_stack().pop() as usize;
if 0 < n && n < self.labels().capacity() {
if self.forward_bitset().contains(n as u32) {
let p = self.labels()[n];
let to_patch = self.compile_branch(p) - mem::size_of::<isize>();
self.labels_mut()[n] = to_patch;
} else if self.resolved_bitset().contains(n as u32) {
let p = self.labels()[n];
let _ = self.compile_branch(p);
} else {
let to_patch = self.compile_branch(0) - mem::size_of::<isize>();
self.labels_mut()[n] = to_patch;
self.forward_bitset_mut().add(n as u32);
}
} else {
self.abort_with(INVALID_NUMERIC_ARGUMENT);
}
}
fn imm_call(&mut self) {
let return_addr = self.data_space().here() + 5 * mem::size_of::<isize>();
self.compile_integer(return_addr as _);
let idx_to_r = self.references().idx_to_r;
self.compile_word(idx_to_r);
self.imm_goto();
}
fn imm_do(&mut self) {
let idx = self.references().idx_do;
self.compile_word(idx);
self.data_space().compile_isize(0);
let here = self.data_space().here();
self.c_stack().push(Control::Do(here, here));
}
fn imm_recurse(&mut self) {
let last = self.wordlist().len() - 1;
self.compile_nest(last);
}
fn imm_qdo(&mut self) {
let idx = self.references().idx_qdo;
self.compile_word(idx);
self.data_space().compile_isize(0);
let here = self.data_space().here();
self.c_stack().push(Control::Do(here, here));
}
fn imm_loop(&mut self) {
let do_part = match self.c_stack().pop() {
Control::Do(do_part, _) => do_part,
_ => {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
return;
}
};
if self.c_stack().underflow() {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
} else {
let idx = self.references().idx_loop;
self.compile_word(idx);
self.data_space().compile_isize(do_part as isize);
let here = self.data_space().here();
unsafe {
self.data_space()
.put_isize(here as isize, (do_part - mem::size_of::<isize>()) as usize);
}
}
}
fn imm_plus_loop(&mut self) {
let do_part = match self.c_stack().pop() {
Control::Do(do_part, _) => do_part,
_ => {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
return;
}
};
if self.c_stack().underflow() {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
} else {
let idx = self.references().idx_plus_loop;
self.compile_word(idx);
self.data_space().compile_isize(do_part as isize);
let here = self.data_space().here();
unsafe {
self.data_space()
.put_isize(here as isize, (do_part - mem::size_of::<isize>()) as usize);
}
}
}
fn activate(&mut self) {
let i = (self.s_stack().pop() - 1) as usize;
if i < NUM_TASKS {
self.set_awake(i, true);
let current_task = self.current_task();
let ip = self.state().instruction_pointer;
self.set_current_task(i);
self.reset();
self.state().instruction_pointer = ip;
self.set_current_task(current_task);
let ip = self.r_stack().pop() as usize;
self.state().instruction_pointer = ip;
} else {
let ip = self.r_stack().pop() as usize;
self.state().instruction_pointer = ip;
self.abort_with(INVALID_NUMERIC_ARGUMENT);
}
}
fn p_i(&mut self) {
match self.r_stack().last() {
Some(it) => {
let next = self.r_stack().len - 2;
match self.r_stack().get(next) {
Some(inext) => {
self.s_stack().push(it.wrapping_add(inext));
}
None => self.abort_with(RETURN_STACK_UNDERFLOW),
}
}
None => self.abort_with(RETURN_STACK_UNDERFLOW),
}
}
fn left_bracket(&mut self) {
self.state().is_compiling = false;
}
fn right_bracket(&mut self) {
self.state().is_compiling = true;
}
fn set_source(&mut self, s: &str) {
let mut buffer = self.input_buffer().take().expect("input buffer");
buffer.clear();
buffer.push_str(s);
self.state().source_index = 0;
self.set_input_buffer(buffer);
}
fn push_source(&mut self, s: &str) {
let mut buffer = self.input_buffer().take().expect("input buffer");
buffer.push_str(s);
self.set_input_buffer(buffer);
}
fn parse_word(&mut self) {
let mut last_token = self.last_token().take().expect("token");
last_token.clear();
if let Some(input_buffer) = self.input_buffer().take() {
if self.state().source_index < input_buffer.len() {
let source = &input_buffer[self.state().source_index..];
let mut cnt = source.len();
let mut char_indices = source.char_indices();
loop {
match char_indices.next() {
Some((idx, ch)) => {
match ch {
'\t' | '\n' | '\r' | ' ' => {
if !last_token.is_empty() {
cnt = idx;
break;
}
}
_ => last_token.push(ch),
};
}
None => {
break;
}
}
}
self.state().source_index = self.state().source_index + cnt;
}
self.set_input_buffer(input_buffer);
}
self.set_last_token(last_token);
}
fn char(&mut self) {
self.parse_word();
let last_token = self.last_token().take().expect("token");
match last_token.chars().nth(0) {
Some(c) => {
self.set_last_token(last_token);
self.s_stack().push(c as isize);
}
None => {
self.set_last_token(last_token);
self.abort_with(UNEXPECTED_END_OF_FILE);
}
}
}
fn bracket_char(&mut self) {
self.char();
if self.last_error().is_some() {
return;
}
let ch = self.s_stack().pop();
self.compile_integer(ch);
}
fn parse(&mut self) {
let input_buffer = self.input_buffer().take().expect("input buffer");
let v = self.s_stack().pop();
let mut last_token = self.last_token().take().expect("token");
last_token.clear();
{
let source = &input_buffer[self.state().source_index..];
let mut cnt = source.len();
let mut char_indices = source.char_indices();
loop {
match char_indices.next() {
Some((idx, ch)) => {
if ch as isize == v {
match char_indices.next() {
Some((idx, _)) => {
cnt = idx;
}
None => {}
}
break;
} else {
last_token.push(ch);
}
}
None => {
break;
}
}
}
self.state().source_index = self.state().source_index + cnt;
}
self.set_last_token(last_token);
self.set_input_buffer(input_buffer);
}
fn _skip(&mut self) {
let input_buffer = self.input_buffer().take().expect("input buffer");
let v = self.s_stack().pop();
{
let source = &input_buffer[self.state().source_index..];
let mut cnt = 0;
let mut char_indices = source.char_indices();
loop {
match char_indices.next() {
Some((idx, ch)) => {
if ch as isize == v {
cnt += 1;
} else {
break;
}
}
None => {
break;
}
}
}
self.state().source_index = self.state().source_index + cnt;
}
self.set_input_buffer(input_buffer);
}
fn imm_paren(&mut self) {
self.s_stack().push(')' as isize);
self.parse();
}
fn imm_backslash(&mut self) {
self.s_stack().push('\n' as isize);
self.parse();
}
fn postpone(&mut self) {
self.parse_word();
let last_token = self.last_token().take().expect("token");
if last_token.is_empty() {
self.set_last_token(last_token);
self.abort_with(UNEXPECTED_END_OF_FILE);
} else {
match self.find(&last_token) {
Some(xt) => {
self.set_last_token(last_token);
self.compile_integer(xt as isize);
let idx = self.references().idx__postpone;
self.compile_word(idx);
}
None => {
self.set_last_token(last_token);
self.abort_with(UNDEFINED_WORD);
}
}
}
}
fn _postpone(&mut self) {
let xt = self.s_stack().pop() as usize;
let compilation_semantics = self.wordlist()[xt].compilation_semantics;
compilation_semantics(self, xt);
}
fn compile_token(&mut self) {
let last_token = self.last_token().take().expect("token");
match self.find(&last_token) {
Some(found_index) => {
self.set_last_token(last_token);
let compilation_semantics = self.wordlist()[found_index].compilation_semantics;
if !self.wordlist()[found_index].is_immediate() {
compilation_semantics(self, found_index);
} else {
self.execute_word(found_index);
}
}
None => {
let mut done = false;
self.set_error(None);
self.evaluate_integer(&last_token);
match self.last_error() {
None => done = true,
Some(_) => {
self.set_error(None);
self.evaluate_float(&last_token);
if self.last_error().is_none() {
done = true;
}
}
}
self.set_last_token(last_token);
if done {
} else {
self.abort_with(UNDEFINED_WORD);
}
}
}
}
fn interpret_token(&mut self) {
let last_token = self.last_token().take().expect("last token");
match self.find(&last_token) {
Some(found_index) => {
self.set_last_token(last_token);
if self.wordlist()[found_index].is_compile_only() {
self.abort_with(INTERPRETING_A_COMPILE_ONLY_WORD);
} else {
self.execute_word(found_index);
}
}
None => {
let mut done = false;
self.set_error(None);
self.evaluate_integer(&last_token);
match self.last_error() {
None => done = true,
Some(_) => {
self.set_error(None);
self.evaluate_float(&last_token);
if self.last_error().is_none() {
done = true;
}
}
}
self.set_last_token(last_token);
if done {
} else {
self.abort_with(UNDEFINED_WORD);
}
}
}
}
fn p_compiling(&mut self) {
let value = if self.state().is_compiling {
TRUE
} else {
FALSE
};
self.s_stack().push(value);
}
fn token_empty(&mut self) {
let value = match self.last_token().as_ref() {
Some(ref t) => {
if t.is_empty() {
TRUE
} else {
FALSE
}
}
None => TRUE,
};
self.s_stack().push(value);
}
fn dot_token(&mut self) {
match self.last_token().take() {
Some(t) => {
match self.output_buffer().as_mut() {
Some(buf) => {
write!(buf, "{}", t).expect("write token");
}
None => {}
}
self.set_last_token(t);
}
None => {}
}
}
fn store_token(&mut self) {
let c_addr = self.s_stack().pop() as usize;
if self.data_space().start() <= c_addr {
match self.last_token().take() {
Some(mut t) => {
self.data_space().put_cstr(&t, c_addr);
t.clear();
self.set_last_token(t);
}
None => unsafe {
if c_addr < self.data_space().limit() {
self.data_space().put_u8(0, c_addr);
} else {
panic!("Error: store_token while space is full.");
}
},
}
} else {
self.abort_with(INVALID_MEMORY_ADDRESS);
}
}
fn evaluate_input(&mut self) {
loop {
self.parse_word();
match self.last_token().as_ref() {
Some(t) => {
if t.is_empty() {
return;
}
}
None => {}
}
if self.state().is_compiling {
self.compile_token();
if self.last_error().is_some() {
break;
}
} else {
self.interpret_token();
if self.last_error().is_some() {
break;
}
}
self.run();
self.check_stacks();
if self.last_error().is_some() {
break;
}
}
}
fn base(&mut self) {
let base_addr = self.data_space().system_variables().base_addr();
self.s_stack().push(base_addr as isize);
}
fn evaluate_integer(&mut self, token: &str) {
let base_addr = self.data_space().system_variables().base_addr();
let default_base = unsafe { self.data_space().get_isize(base_addr) };
match parser::quoted_char(&token.as_bytes()) {
parser::IResult::Done(_bytes, c) => {
if self.state().is_compiling {
self.compile_integer(c);
} else {
self.s_stack().push(c);
}
return;
}
parser::IResult::Err(_) => {
}
}
match parser::base(&token.as_bytes(), default_base) {
parser::IResult::Done(bytes, base) => match parser::sign(&bytes) {
parser::IResult::Done(bytes, sign) => match parser::uint_in_base(&bytes, base) {
parser::IResult::Done(bytes, value) => {
if bytes.len() != 0 {
self.set_error(Some(UNSUPPORTED_OPERATION));
} else {
if self.state().is_compiling {
self.compile_integer(sign.wrapping_mul(value));
} else {
self.s_stack().push(sign.wrapping_mul(value));
}
}
}
parser::IResult::Err(e) => self.set_error(Some(e)),
},
parser::IResult::Err(e) => {
self.set_error(Some(e));
}
},
parser::IResult::Err(e) => {
self.set_error(Some(e));
}
}
}
fn evaluate_float(&mut self, token: &str) {
let significand_sign;
let integer_part;
let mut fraction_part = 0.0;
let mut exponent_sign: isize = 0;
let mut exponent_part: isize = 0;
let mut failed = false;
let mut bytes = token.as_bytes();
match parser::sign(bytes) {
parser::IResult::Done(input, value) => {
significand_sign = value;
bytes = input;
}
parser::IResult::Err(e) => {
self.set_error(Some(e));
return;
}
}
let len_before = bytes.len();
match parser::uint(bytes) {
parser::IResult::Done(input, value) => {
integer_part = value;
bytes = input;
}
parser::IResult::Err(e) => {
self.set_error(Some(e));
return;
}
}
if bytes.len() != len_before {
match parser::fraction(bytes) {
parser::IResult::Done(input, value) => {
fraction_part = value;
bytes = input;
}
parser::IResult::Err(e) => {
self.set_error(Some(e));
return;
}
}
let len_before = bytes.len();
match parser::ascii(bytes, b'E') {
parser::IResult::Done(input, value) => {
if value {
match parser::sign(input) {
parser::IResult::Done(input, value) => {
exponent_sign = value;
bytes = input;
}
parser::IResult::Err(e) => {
self.set_error(Some(e));
return;
}
}
match parser::uint(bytes) {
parser::IResult::Done(input, value) => {
exponent_part = value;
bytes = input;
}
parser::IResult::Err(e) => {
self.set_error(Some(e));
return;
}
}
} else {
match parser::ascii(bytes, b'e') {
parser::IResult::Done(input, value) => {
if value {
match parser::sign(input) {
parser::IResult::Done(input, value) => {
exponent_sign = value;
bytes = input;
}
parser::IResult::Err(e) => {
self.set_error(Some(e));
return;
}
}
match parser::uint(bytes) {
parser::IResult::Done(input, value) => {
exponent_part = value;
bytes = input;
}
parser::IResult::Err(e) => {
self.set_error(Some(e));
return;
}
}
}
}
parser::IResult::Err(e) => {
self.set_error(Some(e));
return;
}
}
}
}
parser::IResult::Err(e) => {
self.set_error(Some(e));
return;
}
}
if bytes.len() == len_before {
failed = true;
}
} else {
failed = true;
}
if bytes.len() != 0 {
failed = true;
}
if failed {
self.set_error(Some(UNSUPPORTED_OPERATION))
} else {
if self.references().idx_flit == 0 {
self.set_error(Some(UNSUPPORTED_OPERATION));
} else {
let value = (significand_sign as f64)
* (integer_part as f64 + fraction_part)
* ((10.0f64).powi((exponent_sign.wrapping_mul(exponent_part)) as i32) as f64);
if self.state().is_compiling {
self.compile_float(value);
} else {
self.f_stack().push(value);
}
}
}
}
fn nest(&mut self) {
let rlen = self.r_stack().len.wrapping_add(1);
self.r_stack().len = rlen;
self.r_stack()[rlen.wrapping_sub(1)] = self.state().instruction_pointer as isize;
let wp = self.state().word_pointer;
self.state().instruction_pointer = self.wordlist()[wp].dfa();
}
fn p_var(&mut self) {
let wp = self.state().word_pointer;
let dfa = self.wordlist()[wp].dfa() as isize;
self.s_stack().push(dfa);
}
fn p_const(&mut self) {
let wp = self.state().word_pointer;
let dfa = self.wordlist()[wp].dfa();
let value = unsafe { self.data_space().get_isize(dfa) as isize };
self.s_stack().push(value);
}
fn define(&mut self, action: fn(&mut Self), compilation_semantics: fn(&mut Self, usize)) {
self.parse_word();
let mut last_token = self.last_token().take().expect("last token");
last_token.make_ascii_lowercase();
if let Some(_) = self.find(&last_token) {
match self.output_buffer().as_mut() {
Some(buf) => {
write!(buf, "Redefining {}", last_token).expect("write");
}
None => {}
}
}
if last_token.is_empty() {
self.set_last_token(last_token);
self.abort_with(UNEXPECTED_END_OF_FILE);
} else {
let nfa = self.data_space().compile_str(&last_token);
self.data_space().align();
let word = Word::new(action, compilation_semantics, nfa, self.data_space().here());
self.wordlist_mut().push(&last_token, word);
self.set_last_token(last_token);
}
}
fn colon(&mut self) {
self.define(Core::nest, Core::compile_nest);
if self.last_error().is_none() {
let def = self.wordlist().last;
self.compile_nest_code(def);
self.wordlist_mut()[def].set_hidden(true);
self.right_bracket();
}
}
fn semicolon(&mut self) {
if self.c_stack().len != 0 {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
} else if self.forward_bitset().layer3() != 0 {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
} else {
let idx = self.references().idx_exit;
let compile = self.wordlist()[idx].compilation_semantics;
compile(self, idx);
let def = self.wordlist().last;
self.wordlist_mut()[def].set_hidden(false);
}
self.left_bracket();
}
fn create(&mut self) {
self.define(Core::p_var, Core::compile_var);
}
fn constant(&mut self) {
let v = self.s_stack().pop();
self.define(Core::p_const, Core::compile_const);
if self.last_error().is_none() {
self.data_space().compile_isize(v as isize);
}
}
fn unmark(&mut self) {
let wp = self.state().word_pointer;
let (nfa, mut dfa) = {
let w = &self.wordlist()[wp];
(w.nfa(), w.dfa())
};
let x = unsafe { self.data_space().get_usize(dfa) };
self.wordlist_mut().last = x;
for i in 0..BUCKET_SIZE {
dfa += mem::size_of::<usize>();
let x = unsafe { self.data_space().get_usize(dfa) };
self.wordlist_mut().buckets[i] = x;
}
self.data_space().truncate(nfa);
self.wordlist_mut().truncate(wp);
}
fn marker(&mut self) {
let x = self.wordlist().last;
self.wordlist_mut().temp_buckets = self.wordlist().buckets;
self.define(Core::unmark, Core::compile_unmark);
self.data_space().compile_usize(x);
for i in 0..BUCKET_SIZE {
let x = self.wordlist().temp_buckets[i];
self.data_space().compile_usize(x);
}
}
fn does(&mut self) {
let idx = self.references().idx__does;
self.s_stack().push(idx as isize);
self.compile_comma();
let idx = self.references().idx_exit;
self.s_stack().push(idx as isize);
self.compile_comma();
}
fn xdoes(&mut self) {
let wp = self.state().word_pointer;
let word = &self.wordlist()[wp];
let dfa = word.dfa();
let doer = word.doer;
self.s_stack().push(dfa as isize);
let ip = self.state().instruction_pointer as isize;
self.r_stack().push(ip);
self.state().instruction_pointer = doer;
}
fn _does(&mut self) {
let doer = self.state().instruction_pointer + mem::size_of::<isize>();
self.data_space().compile_usize(doer);
let def = self.wordlist().last;
let word = &mut self.wordlist_mut()[def];
word.action = Core::xdoes;
word.doer = doer;
}
fn noop(&mut self) {
}
fn p_true(&mut self) {
self.s_stack().push(TRUE);
}
fn p_false(&mut self) {
self.s_stack().push(FALSE);
}
fn char_plus(&mut self) {
let v = self.s_stack().pop();
self.s_stack().push(v + mem::size_of::<u8>() as isize);
}
fn cell_plus(&mut self) {
let v = self.s_stack().pop();
self.s_stack().push(v + mem::size_of::<isize>() as isize);
}
fn cells(&mut self) {
let v = self.s_stack().pop();
self.s_stack().push(v * mem::size_of::<isize>() as isize);
}
fn swap(&mut self) {
let slen = self.s_stack().len;
let t = self.s_stack()[slen.wrapping_sub(1)];
let n = self.s_stack()[slen.wrapping_sub(2)];
self.s_stack()[slen.wrapping_sub(1)] = n;
self.s_stack()[slen.wrapping_sub(2)] = t;
}
fn dup(&mut self) {
let slen = self.s_stack().len.wrapping_add(1);
self.s_stack().len = slen;
self.s_stack()[slen.wrapping_sub(1)] = self.s_stack()[slen.wrapping_sub(2)];
}
fn p_drop(&mut self) {
let slen = self.s_stack().len.wrapping_sub(1);
self.s_stack().len = slen;
}
fn pop_s_stack(&mut self) -> isize {
let slen = self.s_stack().len.wrapping_sub(1);
let t = self.s_stack()[slen];
self.s_stack().len = slen;
t
}
fn nip(&mut self) {
let slen = self.s_stack().len.wrapping_sub(1);
let t = self.s_stack()[slen];
self.s_stack().len = slen;
self.s_stack()[slen.wrapping_sub(1)] = t;
}
fn over(&mut self) {
let slen = self.s_stack().len.wrapping_add(1);
self.s_stack().len = slen;
self.s_stack()[slen.wrapping_sub(1)] = self.s_stack()[slen.wrapping_sub(3)];
}
fn rot(&mut self) {
let slen = self.s_stack().len;
let t = self.s_stack()[slen.wrapping_sub(1)];
let n = self.s_stack()[slen.wrapping_sub(2)];
self.s_stack()[slen.wrapping_sub(1)] = self.s_stack()[slen.wrapping_sub(3)];
self.s_stack()[slen.wrapping_sub(2)] = t;
self.s_stack()[slen.wrapping_sub(3)] = n;
}
fn minus_rot(&mut self) {
let slen = self.s_stack().len;
let t = self.s_stack()[slen.wrapping_sub(1)];
let n = self.s_stack()[slen.wrapping_sub(2)];
self.s_stack()[slen.wrapping_sub(2)] = self.s_stack()[slen.wrapping_sub(3)];
self.s_stack()[slen.wrapping_sub(3)] = t;
self.s_stack()[slen.wrapping_sub(1)] = n;
}
fn pick(&mut self) {
let slen = self.s_stack().len;
let t = self.s_stack()[slen.wrapping_sub(1)] as u8;
let x = self.s_stack()[slen.wrapping_sub(t.wrapping_add(2))];
self.s_stack()[slen.wrapping_sub(1)] = x;
}
fn two_drop(&mut self) {
let slen = self.s_stack().len.wrapping_sub(2);
self.s_stack().len = slen;
}
fn two_dup(&mut self) {
let slen = self.s_stack().len.wrapping_add(2);
self.s_stack().len = slen;
self.s_stack()[slen.wrapping_sub(1)] = self.s_stack()[slen.wrapping_sub(3)];
self.s_stack()[slen.wrapping_sub(2)] = self.s_stack()[slen.wrapping_sub(4)];
}
fn two_swap(&mut self) {
let slen = self.s_stack().len;
let t = self.s_stack()[slen.wrapping_sub(1)];
let n = self.s_stack()[slen.wrapping_sub(2)];
self.s_stack()[slen.wrapping_sub(1)] = self.s_stack()[slen.wrapping_sub(3)];
self.s_stack()[slen.wrapping_sub(2)] = self.s_stack()[slen.wrapping_sub(4)];
self.s_stack()[slen.wrapping_sub(3)] = t;
self.s_stack()[slen.wrapping_sub(4)] = n;
}
fn two_over(&mut self) {
let slen = self.s_stack().len.wrapping_add(2);
self.s_stack().len = slen;
self.s_stack()[slen.wrapping_sub(1)] = self.s_stack()[slen.wrapping_sub(5)];
self.s_stack()[slen.wrapping_sub(2)] = self.s_stack()[slen.wrapping_sub(6)];
}
fn depth(&mut self) {
let len = self.s_stack().len;
self.s_stack().push(len as isize);
}
fn one_plus(&mut self) {
let slen = self.s_stack().len;
let t = self.s_stack()[slen.wrapping_sub(1)];
self.s_stack()[slen.wrapping_sub(1)] = t.wrapping_add(1);
}
fn one_minus(&mut self) {
let slen = self.s_stack().len;
let t = self.s_stack()[slen.wrapping_sub(1)];
self.s_stack()[slen.wrapping_sub(1)] = t.wrapping_sub(1);
}
fn plus(&mut self) {
let slen = self.s_stack().len;
let t = self.s_stack()[slen.wrapping_sub(1)];
let n = self.s_stack()[slen.wrapping_sub(2)];
self.s_stack()[slen.wrapping_sub(2)] = n.wrapping_add(t);
self.s_stack().len = slen.wrapping_sub(1);
}
fn minus(&mut self) {
let slen = self.s_stack().len;
let t = self.s_stack()[slen.wrapping_sub(1)];
let n = self.s_stack()[slen.wrapping_sub(2)];
self.s_stack()[slen.wrapping_sub(2)] = n.wrapping_sub(t);
self.s_stack().len = slen.wrapping_sub(1);
}
fn star(&mut self) {
let slen = self.s_stack().len;
let t = self.s_stack()[slen.wrapping_sub(1)];
let n = self.s_stack()[slen.wrapping_sub(2)];
self.s_stack()[slen.wrapping_sub(2)] = n.wrapping_mul(t);
self.s_stack().len = slen.wrapping_sub(1);
}
fn slash(&mut self) {
let slen = self.s_stack().len;
let t = self.s_stack()[slen.wrapping_sub(1)];
let n = self.s_stack()[slen.wrapping_sub(2)];
if t == 0 {
self.abort_with(DIVISION_BY_ZERO);
} else {
self.s_stack()[slen.wrapping_sub(2)] = n.wrapping_div(t);
self.s_stack().len = slen.wrapping_sub(1);
}
}
fn p_mod(&mut self) {
let slen = self.s_stack().len;
let t = self.s_stack()[slen.wrapping_sub(1)];
let n = self.s_stack()[slen.wrapping_sub(2)];
if t == 0 {
self.abort_with(DIVISION_BY_ZERO);
} else {
self.s_stack()[slen.wrapping_sub(2)] = n.wrapping_rem(t);
self.s_stack().len = slen.wrapping_sub(1);
}
}
fn slash_mod(&mut self) {
let slen = self.s_stack().len;
let t = self.s_stack()[slen.wrapping_sub(1)];
let n = self.s_stack()[slen.wrapping_sub(2)];
if t == 0 {
self.abort_with(DIVISION_BY_ZERO);
} else {
self.s_stack()[slen.wrapping_sub(2)] = n.wrapping_rem(t);
self.s_stack()[slen.wrapping_sub(1)] = n.wrapping_div(t);
}
}
fn abs(&mut self) {
let t = self.s_stack().pop();
self.s_stack().push(t.wrapping_abs());
}
fn negate(&mut self) {
let t = self.s_stack().pop();
self.s_stack().push(t.wrapping_neg());
}
fn zero_less(&mut self) {
let t = self.s_stack().pop();
self.s_stack().push(if t < 0 { TRUE } else { FALSE });
}
fn zero_equals(&mut self) {
let t = self.s_stack().pop();
self.s_stack().push(if t == 0 { TRUE } else { FALSE });
}
fn zero_greater(&mut self) {
let t = self.s_stack().pop();
self.s_stack().push(if t > 0 { TRUE } else { FALSE });
}
fn zero_not_equals(&mut self) {
let t = self.s_stack().pop();
self.s_stack().push(if t == 0 { FALSE } else { TRUE });
}
fn equals(&mut self) {
let (n, t) = self.s_stack().pop2();
self.s_stack().push(if t == n { TRUE } else { FALSE });
}
fn less_than(&mut self) {
let (n, t) = self.s_stack().pop2();
self.s_stack().push(if n < t { TRUE } else { FALSE });
}
fn greater_than(&mut self) {
let (n, t) = self.s_stack().pop2();
self.s_stack().push(if n > t { TRUE } else { FALSE });
}
fn not_equals(&mut self) {
let (n, t) = self.s_stack().pop2();
self.s_stack().push(if n == t { FALSE } else { TRUE });
}
fn within(&mut self) {
let (x1, x2, x3) = self.s_stack().pop3();
self.s_stack()
.push(if x2 <= x1 && x1 < x3 { TRUE } else { FALSE });
}
fn invert(&mut self) {
let t = self.s_stack().pop();
self.s_stack().push(!t);
}
fn and(&mut self) {
let (n, t) = self.s_stack().pop2();
self.s_stack().push(t & n);
}
fn or(&mut self) {
let (n, t) = self.s_stack().pop2();
self.s_stack().push(t | n);
}
fn xor(&mut self) {
let (n, t) = self.s_stack().pop2();
self.s_stack().push(t ^ n);
}
fn lshift(&mut self) {
let (n, t) = self.s_stack().pop2();
self.s_stack().push(n.wrapping_shl(t as u32));
}
fn rshift(&mut self) {
let (n, t) = self.s_stack().pop2();
self.s_stack()
.push(((n as usize).wrapping_shr(t as u32)) as isize);
}
fn exit(&mut self) {
let rlen = self.r_stack().len.wrapping_sub(1);
self.state().instruction_pointer = self.r_stack()[rlen] as usize;
self.r_stack().len = rlen;
}
fn bye(&mut self) {
self.state().instruction_pointer = 0;
}
fn fetch(&mut self) {
let t = self.s_stack().pop() as usize;
if self.data_space().start() < t && t + mem::size_of::<isize>() <= self.data_space().limit()
{
let value = unsafe { self.data_space().get_isize(t as usize) as isize };
self.s_stack().push(value);
} else {
self.abort_with(INVALID_MEMORY_ADDRESS);
}
}
fn store(&mut self) {
let (n, t) = self.s_stack().pop2();
let t = t as usize;
if self.data_space().start() < t && t + mem::size_of::<isize>() <= self.data_space().limit()
{
unsafe { self.data_space().put_isize(n as isize, t as usize) };
} else {
self.abort_with(INVALID_MEMORY_ADDRESS);
}
}
fn c_fetch(&mut self) {
let t = self.s_stack().pop() as usize;
if self.data_space().start() <= t && t < self.data_space().limit() {
let value = unsafe { self.data_space().get_u8(t as usize) as isize };
self.s_stack().push(value);
} else {
self.abort_with(INVALID_MEMORY_ADDRESS);
}
}
fn c_store(&mut self) {
let (n, t) = self.s_stack().pop2();
let t = t as usize;
if self.data_space().start() < t && t < self.data_space().limit() {
unsafe { self.data_space().put_u8(n as u8, t as usize) };
} else {
self.abort_with(INVALID_MEMORY_ADDRESS);
}
}
fn p_move(&mut self) {
let (addr1, addr2, u) = self.s_stack().pop3();
if u > 0 {
let u = u as usize;
let addr1 = addr1 as usize;
let addr2 = addr2 as usize;
if self.data_space().start() < addr1
&& addr1 + u <= self.data_space().limit()
&& self.data_space().start() < addr2
&& addr2 + u <= self.data_space().limit()
{
unsafe {
if addr1 < addr2 {
for p in (addr1..(addr1 + u))
.into_iter()
.zip(addr2..(addr2 + u))
.rev()
{
let value = self.data_space().get_u8(p.0);
self.data_space().put_u8(value, p.1);
}
} else {
for p in (addr1..(addr1 + u)).into_iter().zip(addr2..(addr2 + u)) {
let value = self.data_space().get_u8(p.0);
self.data_space().put_u8(value, p.1);
}
}
}
} else {
self.abort_with(INVALID_MEMORY_ADDRESS);
}
}
}
fn tick(&mut self) {
self.parse_word();
let last_token = self.last_token().take().expect("last token");
if last_token.is_empty() {
self.set_last_token(last_token);
self.abort_with(UNEXPECTED_END_OF_FILE);
} else {
match self.find(&last_token) {
Some(found_index) => {
self.s_stack().push(found_index as isize);
self.set_last_token(last_token);
}
None => {
self.set_last_token(last_token);
self.abort_with(UNDEFINED_WORD);
}
}
}
}
fn to_body(&mut self) {
let t = self.s_stack().pop() as usize;
if t < self.wordlist().len() {
let dfa = self.wordlist()[t].dfa() as isize;
self.s_stack().push(dfa);
} else {
self.abort_with(INVALID_NUMERIC_ARGUMENT);
}
}
fn to_name(&mut self) {
let t = self.s_stack().pop() as usize;
if t < self.wordlist().len() {
let nfa = self.wordlist()[t].nfa() as isize;
self.s_stack().push(nfa);
} else {
self.abort_with(INVALID_NUMERIC_ARGUMENT);
}
}
fn execute(&mut self) {
let t = self.s_stack().pop();
self.execute_word(t as usize);
}
fn bracket_tick(&mut self) {
self.parse_word();
let last_token = self.last_token().take().expect("last token");
if last_token.is_empty() {
self.set_last_token(last_token);
self.abort_with(UNEXPECTED_END_OF_FILE);
} else {
match self.find(&last_token) {
Some(found_index) => {
self.compile_integer(found_index as isize);
self.set_last_token(last_token);
}
None => {
self.set_last_token(last_token);
self.abort_with(UNDEFINED_WORD);
}
}
}
}
fn compile_comma(&mut self) {
let v = self.s_stack().pop();
self.data_space().compile_isize(v as isize);
}
fn here(&mut self) {
let here = self.data_space().here() as isize;
self.s_stack().push(here);
}
fn allot(&mut self) {
let v = self.s_stack().pop();
self.data_space().allot(v);
}
fn aligned(&mut self) {
let pos = self.s_stack().pop();
let pos = DataSpace::aligned(pos as usize);
self.s_stack().push(pos as isize);
}
fn align(&mut self) {
self.data_space().align();
}
fn comma(&mut self) {
let v = self.s_stack().pop();
self.data_space().compile_isize(v as isize);
}
fn p_to_r(&mut self) {
let slen = self.s_stack().len;
let rlen = self.r_stack().len.wrapping_add(1);
self.r_stack().len = rlen;
self.r_stack()[rlen.wrapping_sub(1)] = self.s_stack()[slen.wrapping_sub(1)];
self.s_stack().len = slen.wrapping_sub(1);
}
fn r_from(&mut self) {
let slen = self.s_stack().len.wrapping_add(1);
let rlen = self.r_stack().len;
self.s_stack().len = slen;
self.s_stack()[slen.wrapping_sub(1)] = self.r_stack()[rlen.wrapping_sub(1)];
self.r_stack().len = rlen.wrapping_sub(1);
}
fn r_fetch(&mut self) {
let slen = self.s_stack().len.wrapping_add(1);
let rlen = self.r_stack().len;
self.s_stack().len = slen;
self.s_stack()[slen.wrapping_sub(1)] = self.r_stack()[rlen.wrapping_sub(1)];
}
fn two_to_r(&mut self) {
let slen = self.s_stack().len;
let rlen = self.r_stack().len.wrapping_add(2);
self.r_stack().len = rlen;
self.r_stack()[rlen.wrapping_sub(2)] = self.s_stack()[slen.wrapping_sub(2)];
self.r_stack()[rlen.wrapping_sub(1)] = self.s_stack()[slen.wrapping_sub(1)];
self.s_stack().len = slen.wrapping_sub(2);
}
fn two_r_from(&mut self) {
let slen = self.s_stack().len.wrapping_add(2);
let rlen = self.r_stack().len;
self.s_stack().len = slen;
self.s_stack()[slen.wrapping_sub(2)] = self.r_stack()[rlen.wrapping_sub(2)];
self.s_stack()[slen.wrapping_sub(1)] = self.r_stack()[rlen.wrapping_sub(1)];
self.r_stack().len = rlen.wrapping_sub(2);
}
fn two_r_fetch(&mut self) {
let slen = self.s_stack().len.wrapping_add(2);
let rlen = self.r_stack().len;
self.s_stack().len = slen;
self.s_stack()[slen.wrapping_sub(2)] = self.r_stack()[rlen.wrapping_sub(2)];
self.s_stack()[slen.wrapping_sub(1)] = self.r_stack()[rlen.wrapping_sub(1)];
}
fn check_stacks(&mut self) {
if self.s_stack().overflow() {
self.abort_with(STACK_OVERFLOW);
} else if self.s_stack().underflow() {
self.abort_with(STACK_UNDERFLOW);
} else if self.r_stack().overflow() {
self.abort_with(RETURN_STACK_OVERFLOW);
} else if self.r_stack().underflow() {
self.abort_with(RETURN_STACK_UNDERFLOW);
} else if self.c_stack().overflow() {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
} else if self.c_stack().underflow() {
self.abort_with(CONTROL_STRUCTURE_MISMATCH);
} else if self.f_stack().overflow() {
self.abort_with(FLOATING_POINT_STACK_OVERFLOW);
} else if self.f_stack().underflow() {
self.abort_with(FLOATING_POINT_STACK_UNDERFLOW);
}
}
fn handler_store(&mut self) {
let t = self.s_stack().pop();
self.set_handler(t as usize);
}
fn error(&mut self) {
match self.last_error() {
Some(e) => {
self.s_stack().push(e.into());
}
None => {
self.s_stack().push(0);
}
}
}
fn clear_error(&mut self) {
self.set_error(None);
}
fn dot_error(&mut self) {
match self.last_error() {
Some(e) => match self.output_buffer().as_mut() {
Some(buf) => {
write!(buf, "{}", exception::description(e)).expect("write");
}
None => {}
},
None => {}
}
}
fn clear_stacks(&mut self) {
self.s_stack().reset();
self.f_stack().reset();
self.c_stack().reset();
}
fn p_source_id(&mut self) {
let source_id = self.source_id();
self.s_stack().push(source_id);
}
fn p_set_source_id(&mut self) {
let id = self.s_stack().pop();
self.set_source_id(id);
}
fn set_source_id(&mut self, id: isize) {
if id > 0 {
if id - 1 < self.sources().len() as isize
&& self.sources()[id as usize - 1].is_some()
&& self.lines()[id as usize - 1].is_some()
{
self.state().source_id = id;
} else {
self.abort_with(INVALID_NUMERIC_ARGUMENT);
}
} else if id == 0 {
self.state().source_id = id;
} else {
self.abort_with(INVALID_NUMERIC_ARGUMENT);
}
}
fn p_source_idx(&mut self) {
let source_idx = self.state().source_index as isize;
self.s_stack().push(source_idx);
}
fn p_set_source_idx(&mut self) {
let idx = self.s_stack().pop() as usize;
self.state().source_index = idx;
}
fn reset(&mut self) {
self.r_stack().reset();
self.set_source_id(0);
if let Some(ref mut buf) = *self.input_buffer() {
buf.clear()
}
self.state().aborted_word_pointer = 0;
self.state().source_index = 0;
self.left_bracket();
self.set_error(None);
}
fn abort_with(&mut self, e: Exception) {
self.clear_stacks();
self.set_error(Some(e));
let h = self.handler();
self.state().aborted_word_pointer = self.state().word_pointer;
self.execute_word(h);
}
fn abort(&mut self) {
self.abort_with(ABORT);
}
fn pause(&mut self) {
let mut i = self.current_task();
loop {
i = (i + 1) % NUM_TASKS;
if self.awake(i) {
self.set_current_task(i);
break;
}
}
}
fn me(&mut self) {
let me = self.current_task() + 1;
self.s_stack().push(me as isize);
}
fn suspend(&mut self) {
let i = (self.s_stack().pop() - 1) as usize;
if i < NUM_TASKS {
self.set_awake(i as usize, false);
} else {
self.abort_with(INVALID_NUMERIC_ARGUMENT);
}
}
fn resume(&mut self) {
let i = (self.s_stack().pop() - 1) as usize;
if i < NUM_TASKS {
self.set_awake(i as usize, true);
} else {
self.abort_with(INVALID_NUMERIC_ARGUMENT);
}
}
}
#[cfg(test)]
mod tests {
extern crate test;
use self::test::Bencher;
use super::{Core, Memory};
use exception::{
ABORT, CONTROL_STRUCTURE_MISMATCH, INTERPRETING_A_COMPILE_ONLY_WORD,
INVALID_MEMORY_ADDRESS, RETURN_STACK_UNDERFLOW, STACK_UNDERFLOW, UNDEFINED_WORD,
UNEXPECTED_END_OF_FILE, UNSUPPORTED_OPERATION,
};
use loader::HasLoader;
use mock_vm::VM;
use std::mem;
#[bench]
fn bench_noop(b: &mut Bencher) {
let vm = &mut VM::new();
b.iter(|| vm.noop());
}
#[test]
fn test_find() {
let vm = &mut VM::new();
assert!(vm.find("").is_none());
assert!(vm.find("word-not-exist").is_none());
vm.find("noop").expect("noop not found");
}
#[bench]
fn bench_find_word_not_exist(b: &mut Bencher) {
let vm = &mut VM::new();
b.iter(|| vm.find("unknown"));
}
#[bench]
fn bench_find_word_at_beginning_of_wordlist(b: &mut Bencher) {
let vm = &mut VM::new();
b.iter(|| vm.find("noop"));
}
#[bench]
fn bench_inner_interpreter_without_nest(b: &mut Bencher) {
let vm = &mut VM::new();
let ip = vm.data_space().here();
let idx = vm.find("noop").expect("noop not exists");
vm.compile_word(idx);
vm.compile_word(idx);
vm.compile_word(idx);
vm.compile_word(idx);
vm.compile_word(idx);
vm.compile_word(idx);
vm.compile_word(idx);
b.iter(|| {
vm.state().instruction_pointer = ip;
vm.run();
});
}
#[test]
fn test_drop() {
let vm = &mut VM::new();
vm.p_drop();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.p_drop();
vm.check_stacks();
assert!(vm.s_stack().is_empty());
assert!(vm.last_error().is_none());
}
#[bench]
fn bench_drop(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(1);
b.iter(|| {
vm.p_drop();
vm.s_stack().push(1);
});
}
#[test]
fn test_nip() {
let vm = &mut VM::new();
vm.nip();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.nip();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.nip();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert!(vm.s_stack().len() == 1);
assert!(vm.s_stack().last() == Some(2));
}
#[bench]
fn bench_nip(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(1);
vm.s_stack().push(1);
b.iter(|| {
vm.nip();
vm.s_stack().push(1);
});
}
#[test]
fn test_swap() {
let vm = &mut VM::new();
vm.swap();
vm.check_stacks();
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.swap();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.swap();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 2);
assert_eq!(vm.s_stack().pop(), 1);
assert_eq!(vm.s_stack().pop(), 2);
vm.check_stacks();
assert!(vm.last_error().is_none());
}
#[bench]
fn bench_swap(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(1);
vm.s_stack().push(2);
b.iter(|| vm.swap());
}
#[test]
fn test_dup() {
let vm = &mut VM::new();
vm.dup();
vm.check_stacks();
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.dup();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 2);
assert_eq!(vm.s_stack().pop(), 1);
assert_eq!(vm.s_stack().pop(), 1);
vm.check_stacks();
assert!(vm.last_error().is_none());
}
#[bench]
fn bench_dup(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(1);
b.iter(|| {
vm.dup();
vm.s_stack().pop();
});
}
#[test]
fn test_over() {
let vm = &mut VM::new();
vm.over();
vm.check_stacks();
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.check_stacks();
vm.over();
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.over();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 3);
assert_eq!(vm.s_stack().pop(), 1);
assert_eq!(vm.s_stack().pop(), 2);
assert_eq!(vm.s_stack().pop(), 1);
vm.check_stacks();
assert!(vm.last_error().is_none());
}
#[bench]
fn bench_over(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(1);
vm.s_stack().push(2);
b.iter(|| {
vm.over();
vm.s_stack().pop();
});
}
#[test]
fn test_rot() {
let vm = &mut VM::new();
vm.rot();
vm.check_stacks();
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.rot();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.rot();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.s_stack().push(3);
vm.rot();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 3);
assert_eq!(vm.s_stack().pop(), 1);
assert_eq!(vm.s_stack().pop(), 3);
assert_eq!(vm.s_stack().pop(), 2);
vm.check_stacks();
assert!(vm.last_error().is_none());
}
#[bench]
fn bench_rot(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.s_stack().push(3);
b.iter(|| vm.rot());
}
#[test]
fn test_pick() {
let vm = &mut VM::new();
vm.s_stack().push(0);
vm.s_stack().push(0);
vm.pick();
vm.check_stacks();
assert_eq!(vm.last_error(), None);
assert_eq!(vm.s_stack().as_slice(), [0, 0]);
let vm = &mut VM::new();
vm.s_stack().push(1);
vm.s_stack().push(0);
vm.s_stack().push(1);
vm.pick();
vm.check_stacks();
assert_eq!(vm.last_error(), None);
assert_eq!(vm.s_stack().as_slice(), [1, 0, 1]);
let vm = &mut VM::new();
vm.s_stack().push(2);
vm.s_stack().push(1);
vm.s_stack().push(0);
vm.s_stack().push(2);
vm.pick();
vm.check_stacks();
assert_eq!(vm.last_error(), None);
assert_eq!(vm.s_stack().as_slice(), [2, 1, 0, 2]);
}
#[test]
fn test_2drop() {
let vm = &mut VM::new();
vm.two_drop();
assert!(vm.s_stack().underflow());
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.two_drop();
assert!(vm.s_stack().underflow());
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.two_drop();
assert!(!vm.s_stack().underflow());
assert!(!vm.s_stack().overflow());
assert!(vm.last_error().is_none());
assert!(vm.s_stack().is_empty());
}
#[bench]
fn bench_2drop(b: &mut Bencher) {
let vm = &mut VM::new();
b.iter(|| {
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.two_drop();
});
}
#[test]
fn test_2dup() {
let vm = &mut VM::new();
vm.two_dup();
assert!(!vm.s_stack().underflow());
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.two_dup();
assert!(!vm.s_stack().underflow());
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.two_dup();
assert!(!vm.s_stack().underflow());
assert!(!vm.s_stack().overflow());
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 4);
assert_eq!(vm.s_stack().pop(), 2);
assert_eq!(vm.s_stack().pop(), 1);
assert_eq!(vm.s_stack().pop(), 2);
assert_eq!(vm.s_stack().pop(), 1);
}
#[bench]
fn bench_2dup(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(1);
vm.s_stack().push(2);
b.iter(|| {
vm.two_dup();
vm.two_drop();
});
}
#[test]
fn test_2swap() {
let vm = &mut VM::new();
vm.two_swap();
assert!(!vm.s_stack().underflow());
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.two_swap();
assert!(!vm.s_stack().underflow());
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.two_swap();
assert!(vm.s_stack().underflow());
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.s_stack().push(3);
vm.two_swap();
assert!(vm.s_stack().underflow());
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.s_stack().push(3);
vm.s_stack().push(4);
vm.two_swap();
assert!(!vm.s_stack().underflow());
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 4);
assert_eq!(vm.s_stack().pop(), 2);
assert_eq!(vm.s_stack().pop(), 1);
assert_eq!(vm.s_stack().pop(), 4);
assert_eq!(vm.s_stack().pop(), 3);
}
#[bench]
fn bench_2swap(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.s_stack().push(3);
vm.s_stack().push(4);
b.iter(|| vm.two_swap());
}
#[test]
fn test_2over() {
let vm = &mut VM::new();
vm.two_over();
assert!(!vm.s_stack().underflow());
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.two_over();
assert!(!vm.s_stack().underflow());
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.two_over();
assert!(!vm.s_stack().underflow());
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.s_stack().push(3);
vm.two_over();
assert!(!vm.s_stack().underflow());
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.s_stack().push(3);
vm.s_stack().push(4);
vm.two_over();
assert!(!vm.s_stack().underflow());
assert!(!vm.s_stack().overflow());
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 6);
assert_eq!(vm.s_stack().as_slice(), [1, 2, 3, 4, 1, 2]);
}
#[bench]
fn bench_2over(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.s_stack().push(3);
vm.s_stack().push(4);
b.iter(|| {
vm.two_over();
vm.two_drop();
});
}
#[test]
fn test_depth() {
let vm = &mut VM::new();
vm.depth();
vm.depth();
vm.depth();
assert_eq!(vm.s_stack().as_slice(), [0, 1, 2]);
}
#[test]
fn test_one_plus() {
let vm = &mut VM::new();
vm.one_plus();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.one_plus();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 2);
}
#[bench]
fn bench_one_plus(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(0);
b.iter(|| {
vm.one_plus();
});
}
#[test]
fn test_one_minus() {
let vm = &mut VM::new();
vm.one_minus();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(2);
vm.one_minus();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 1);
}
#[bench]
fn bench_one_minus(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(0);
b.iter(|| {
vm.one_minus();
});
}
#[test]
fn test_minus() {
let vm = &mut VM::new();
vm.minus();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(5);
vm.minus();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(5);
vm.s_stack().push(7);
vm.minus();
vm.check_stacks();
assert_eq!(vm.last_error(), None);
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -2);
}
#[bench]
fn bench_minus(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(0);
b.iter(|| {
vm.dup();
vm.minus();
});
}
#[test]
fn test_plus() {
let vm = &mut VM::new();
vm.plus();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(5);
vm.plus();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(5);
vm.s_stack().push(7);
vm.plus();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 12);
}
#[bench]
fn bench_plus(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(1);
b.iter(|| {
vm.dup();
vm.plus();
});
}
#[test]
fn test_star() {
let vm = &mut VM::new();
vm.star();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(5);
vm.star();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(5);
vm.s_stack().push(7);
vm.star();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 35);
}
#[bench]
fn bench_star(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(1);
b.iter(|| {
vm.dup();
vm.star();
});
}
#[test]
fn test_slash() {
let vm = &mut VM::new();
vm.slash();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(30);
vm.slash();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(30);
vm.s_stack().push(7);
vm.slash();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 4);
}
#[bench]
fn bench_slash(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(1);
b.iter(|| {
vm.dup();
vm.slash();
});
}
#[test]
fn test_mod() {
let vm = &mut VM::new();
vm.p_mod();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(30);
vm.p_mod();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(30);
vm.s_stack().push(7);
vm.p_mod();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 2);
}
#[bench]
fn bench_mod(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push(1);
vm.s_stack().push(2);
b.iter(|| {
vm.p_mod();
vm.s_stack().push(2);
});
}
#[test]
fn test_slash_mod() {
let vm = &mut VM::new();
vm.slash_mod();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(30);
vm.slash_mod();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(30);
vm.s_stack().push(7);
vm.slash_mod();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 2);
assert_eq!(vm.s_stack().pop(), 4);
assert_eq!(vm.s_stack().pop(), 2);
}
#[bench]
fn bench_slash_mod(b: &mut Bencher) {
let vm = &mut VM::new();
vm.s_stack().push2(1, 2);
b.iter(|| {
vm.slash_mod();
vm.p_drop();
vm.s_stack().push(2);
});
}
#[test]
fn test_abs() {
let vm = &mut VM::new();
vm.s_stack().push(-30);
vm.abs();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 30);
}
#[test]
fn test_negate() {
let vm = &mut VM::new();
vm.negate();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(30);
vm.negate();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -30);
}
#[test]
fn test_zero_less() {
let vm = &mut VM::new();
vm.zero_less();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(-1);
vm.zero_less();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -1);
vm.s_stack().push(0);
vm.zero_less();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
}
#[test]
fn test_zero_equals() {
let vm = &mut VM::new();
vm.zero_equals();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(0);
vm.zero_equals();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -1);
vm.s_stack().push(-1);
vm.zero_equals();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
vm.s_stack().push(1);
vm.zero_equals();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
}
#[test]
fn test_zero_greater() {
let vm = &mut VM::new();
vm.zero_greater();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.zero_greater();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -1);
vm.s_stack().push(0);
vm.zero_greater();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
}
#[test]
fn test_zero_not_equals() {
let vm = &mut VM::new();
vm.zero_not_equals();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(0);
vm.zero_not_equals();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
vm.s_stack().push(-1);
vm.zero_not_equals();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -1);
vm.s_stack().push(1);
vm.zero_not_equals();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -1);
}
#[test]
fn test_less_than() {
let vm = &mut VM::new();
vm.less_than();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(-1);
vm.less_than();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(-1);
vm.s_stack().push(0);
vm.less_than();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -1);
vm.s_stack().push(0);
vm.s_stack().push(0);
vm.less_than();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
}
#[test]
fn test_equals() {
let vm = &mut VM::new();
vm.equals();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(0);
vm.equals();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(0);
vm.s_stack().push(0);
vm.equals();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -1);
vm.s_stack().push(-1);
vm.s_stack().push(0);
vm.equals();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
vm.s_stack().push(1);
vm.s_stack().push(0);
vm.equals();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
}
#[test]
fn test_greater_than() {
let vm = &mut VM::new();
vm.greater_than();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.greater_than();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(0);
vm.greater_than();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -1);
vm.s_stack().push(0);
vm.s_stack().push(0);
vm.greater_than();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
}
#[test]
fn test_not_equals() {
let vm = &mut VM::new();
vm.not_equals();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(0);
vm.not_equals();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(0);
vm.s_stack().push(0);
vm.not_equals();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
vm.s_stack().push(-1);
vm.s_stack().push(0);
vm.not_equals();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -1);
vm.s_stack().push(1);
vm.s_stack().push(0);
vm.not_equals();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -1);
}
#[test]
fn test_within() {
let vm = &mut VM::new();
vm.within();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.within();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(1);
vm.within();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.within();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -1);
vm.s_stack().push(1);
vm.s_stack().push(0);
vm.s_stack().push(1);
vm.within();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
vm.s_stack().push(0);
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.within();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
vm.s_stack().push(3);
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.within();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
}
#[test]
fn test_invert() {
let vm = &mut VM::new();
vm.invert();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(707);
vm.invert();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -708);
}
#[test]
fn test_and() {
let vm = &mut VM::new();
vm.s_stack().push(707);
vm.s_stack().push(007);
vm.and();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert!(!vm.s_stack().overflow());
assert!(!vm.s_stack().underflow());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 3);
}
#[test]
fn test_or() {
let vm = &mut VM::new();
vm.or();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(707);
vm.or();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(707);
vm.s_stack().push(07);
vm.or();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 711);
}
#[test]
fn test_xor() {
let vm = &mut VM::new();
vm.xor();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(707);
vm.xor();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(707);
vm.s_stack().push(07);
vm.xor();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 708);
}
#[test]
fn test_lshift() {
let vm = &mut VM::new();
vm.lshift();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.lshift();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(1);
vm.s_stack().push(1);
vm.lshift();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 2);
vm.s_stack().push(1);
vm.s_stack().push(2);
vm.lshift();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 4);
}
#[test]
fn test_rshift() {
let vm = &mut VM::new();
vm.rshift();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(8);
vm.rshift();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.s_stack().push(8);
vm.s_stack().push(1);
vm.rshift();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 4);
vm.s_stack().push(-1);
vm.s_stack().push(1);
vm.rshift();
vm.check_stacks();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert!(vm.s_stack().pop() > 0);
}
#[test]
fn test_parse_word() {
let vm = &mut VM::new();
vm.set_source("hello world\t\r\n\"");
vm.parse_word();
assert_eq!(vm.last_token().clone().unwrap(), "hello");
assert_eq!(vm.state().source_index, 5);
vm.parse_word();
assert_eq!(vm.last_token().clone().unwrap(), "world");
assert_eq!(vm.state().source_index, 11);
vm.parse_word();
assert_eq!(vm.last_token().clone().unwrap(), "\"");
}
#[test]
fn test_evaluate_input() {
let vm = &mut VM::new();
vm.set_source(">r");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(INTERPRETING_A_COMPILE_ONLY_WORD));
vm.reset();
vm.clear_stacks();
vm.set_source("drop");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.set_source(": 4drop drop drop drop drop ; 4drop");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.set_source("xdrop");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(UNDEFINED_WORD));
vm.reset();
vm.clear_stacks();
vm.set_source("false true dup 1+ 2 -3");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 5);
assert_eq!(vm.s_stack().pop(), -3);
assert_eq!(vm.s_stack().pop(), 2);
assert_eq!(vm.s_stack().pop(), 0);
assert_eq!(vm.s_stack().pop(), -1);
assert_eq!(vm.s_stack().pop(), 0);
}
#[test]
fn test_push_source() {
let mut vm = VM::new();
vm.set_source(": x");
vm.push_source(" ");
vm.push_source("1");
vm.push_source(" ");
vm.push_source(";");
assert_eq!(vm.input_buffer(), &Some(": x 1 ;".to_owned()));
}
#[test]
fn test_colon_and_semi_colon() {
let vm = &mut VM::new();
vm.set_source(":");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(UNEXPECTED_END_OF_FILE));
vm.reset();
vm.clear_stacks();
vm.set_source(": 2+3 2 3 + ; 2+3");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 5);
}
#[test]
fn test_constant() {
let vm = &mut VM::new();
vm.set_source("constant");
vm.evaluate_input();
vm.reset();
vm.clear_stacks();
vm.set_source("5 constant x x x");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 2);
assert_eq!(vm.s_stack().pop(), 5);
assert_eq!(vm.s_stack().pop(), 5);
}
#[test]
fn test_constant_in_colon() {
let vm = &mut VM::new();
vm.set_source("77 constant x : 2x x 2 * ; 2x");
vm.evaluate_input();
vm.run();
assert_eq!(vm.s_stack().pop(), 154);
assert_eq!(vm.s_stack().len, 0);
}
#[test]
fn test_create_and_store_fetch() {
let vm = &mut VM::new();
vm.set_source("@");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(INVALID_MEMORY_ADDRESS));
vm.reset();
vm.clear_stacks();
vm.set_source("!");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(INVALID_MEMORY_ADDRESS));
vm.reset();
vm.clear_stacks();
vm.set_source("create x 1 cells allot x !");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.set_source("create x 1 cells allot x @ 3 x ! x @");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 2);
assert_eq!(vm.s_stack().pop(), 3);
assert_eq!(vm.s_stack().pop(), 0);
}
#[test]
fn test_create_and_fetch_in_colon() {
let vm = &mut VM::new();
vm.set_source("create x 1 cells allot 7 x ! : x@ x @ ; x@");
vm.evaluate_input();
vm.run();
assert_eq!(vm.s_stack().pop(), 7);
assert_eq!(vm.s_stack().len, 0);
}
#[test]
fn test_create_in_colon() {
let vm = &mut VM::new();
vm.set_source("create x 7 , : x@ x @ ; x@");
vm.evaluate_input();
vm.run();
assert_eq!(vm.s_stack().pop(), 7);
assert_eq!(vm.s_stack().len, 0);
}
#[test]
fn test_char_plus() {
let vm = &mut VM::new();
vm.char_plus();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.set_source("2 char+");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().as_slice(), [3]);
}
#[test]
fn test_cell_plus_and_cells() {
let vm = &mut VM::new();
vm.cell_plus();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.cells();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.set_source("2 cell+ 9 cells");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(
vm.s_stack().as_slice(),
[
2 + mem::size_of::<isize>() as isize,
9 * mem::size_of::<isize>() as isize
]
);
}
#[test]
fn test_tick() {
let vm = &mut VM::new();
vm.tick();
assert_eq!(vm.last_error(), Some(UNEXPECTED_END_OF_FILE));
vm.reset();
vm.set_source("' xdrop");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(UNDEFINED_WORD));
vm.reset();
vm.clear_stacks();
vm.set_source("' drop");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
}
#[test]
fn test_execute() {
let vm = &mut VM::new();
vm.execute();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(UNSUPPORTED_OPERATION));
vm.reset();
vm.clear_stacks();
vm.set_source("' drop");
vm.evaluate_input();
vm.execute();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.set_source("1 2 ' swap execute");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 2);
assert_eq!(vm.s_stack().pop(), 1);
assert_eq!(vm.s_stack().pop(), 2);
}
#[test]
fn test_here_allot() {
let vm = &mut VM::new();
vm.allot();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
vm.set_source("here 2 cells allot here -");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(
vm.s_stack().pop(),
-((mem::size_of::<isize>() * 2) as isize)
);
}
#[test]
fn test_to_r_r_fetch_r_from() {
let vm = &mut VM::new();
vm.set_source(": t 3 >r 2 r@ + r> + ; t");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 8);
}
#[bench]
fn bench_to_r_r_fetch_r_from(b: &mut Bencher) {
let vm = &mut VM::new();
vm.set_source(": main 3 >r r@ drop r> drop ;");
vm.evaluate_input();
vm.set_source("' main");
vm.evaluate_input();
b.iter(|| {
vm.dup();
vm.execute();
vm.run();
});
}
#[test]
fn test_two_to_r_two_r_fetch_two_r_from() {
let vm = &mut VM::new();
vm.set_source(": t 1 2 2>r 2r@ + 2r> - * ; t");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -3);
}
#[bench]
fn bench_two_to_r_two_r_fetch_two_r_from(b: &mut Bencher) {
let vm = &mut VM::new();
vm.set_source(": main 1 2 2>r 2r@ 2drop 2r> 2drop ;");
vm.evaluate_input();
vm.set_source("' main");
vm.evaluate_input();
b.iter(|| {
vm.dup();
vm.execute();
vm.run();
});
}
#[test]
fn test_if_then() {
let vm = &mut VM::new();
vm.set_source(": t5 if ;");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": t4 then ; t4");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": t1 0 dup if drop -1 then ; t1");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
vm.reset();
vm.clear_stacks();
vm.set_source(": t1 -1 dup if drop -1 then ; t1");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -1);
}
#[test]
fn test_if_else_then() {
let vm = &mut VM::new();
vm.set_source(": t3 else then ;");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": t1 0 if true else false then ; t1");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 0);
vm.set_source(": t2 1 if true else false then ; t2");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -1);
}
#[test]
fn test_begin_again() {
let vm = &mut VM::new();
vm.set_source(": t3 begin ;");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": t2 again ;");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": t1 0 begin 1+ dup 3 = if exit then again ; t1");
vm.evaluate_input();
assert_eq!(vm.last_error(), None);
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 3);
}
#[test]
fn test_begin_while_repeat() {
let vm = &mut VM::new();
vm.set_source(": t1 begin ;");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": t2 while ;");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": t3 repeat ;");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": t4 begin while ;");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": t5 begin repeat ;");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": t6 while repeat ;");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": t7 0 begin 1+ dup 3 <> while repeat ; t7");
vm.evaluate_input();
assert_eq!(vm.last_error(), None);
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 3);
}
#[test]
fn test_label_goto_call() {
let vm = &mut VM::new();
vm.set_source(
": test1 0labels 0 [ 10 ] label 1+ dup 3 > if exit then [ 10 ] goto ; test1",
);
vm.evaluate_input();
assert_eq!(vm.s_stack().pop(), 4);
vm.clear_stacks();
vm.set_source(": test2 0labels [ 10 ] goto 1 [ 10 ] label 2 3 ; test2");
vm.evaluate_input();
assert_eq!(vm.s_stack().len(), 2);
vm.clear_stacks();
vm.set_source(": test3 0labels [ 10 ] goto [ 20 ] label 2 3 exit [ 10 ] label [ 20 ] call 4 5 ; test3");
vm.evaluate_input();
assert_eq!(vm.s_stack().len(), 4);
vm.clear_stacks();
vm.set_source(": test4 0labels [ 10 ] call 1 exit [ 10 ] label 2 3 ; test4");
vm.evaluate_input();
assert_eq!(vm.s_stack().len(), 3);
assert_eq!(vm.s_stack().pop(), 1);
vm.clear_stacks();
vm.set_source(": test5 0labels [ 10 ] call ; test5");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.clear_stacks();
vm.clear_error();
vm.set_source(": test6 [ 0 ] goto ;");
vm.evaluate_input();
assert!(vm.last_error() != None);
vm.clear_stacks();
vm.clear_error();
vm.set_source(": test7 [ 0 ] label ;");
vm.evaluate_input();
assert!(vm.last_error() != None);
vm.clear_stacks();
vm.clear_error();
vm.set_source(": test8 [ 0 ] call ;");
vm.evaluate_input();
assert!(vm.last_error() != None);
}
#[test]
fn test_backslash() {
let vm = &mut VM::new();
vm.set_source("1 2 3 \\ 5 6 7");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 3);
assert_eq!(vm.s_stack().pop(), 3);
assert_eq!(vm.s_stack().pop(), 2);
assert_eq!(vm.s_stack().pop(), 1);
}
#[test]
fn test_marker_unmark() {
let vm = &mut VM::new();
let wordlist_len = vm.wordlist().len();
vm.set_source("here marker empty empty here =");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), -1);
assert_eq!(vm.wordlist().len(), wordlist_len);
}
#[test]
fn test_abort() {
let vm = &mut VM::new();
vm.set_source("1 2 3 abort 5 6 7");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(ABORT));
assert_eq!(vm.s_stack().len(), 0);
}
#[test]
fn test_do_loop() {
let vm = &mut VM::new();
vm.set_source(": t1 do ;");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": t2 loop ;");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": main 1 5 0 do 1+ loop ; main");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 6);
}
#[test]
fn test_do_unloop_exit_loop() {
let vm = &mut VM::new();
vm.set_source(": t1 unloop ; t1");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(RETURN_STACK_UNDERFLOW));
vm.reset();
vm.clear_stacks();
vm.set_source(": main 1 5 0 do 1+ dup 3 = if unloop exit then loop ; main");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 3);
}
#[test]
fn test_do_plus_loop() {
let vm = &mut VM::new();
vm.set_source(": t1 +loop ;");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": t2 5 0 do +loop ; t2");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.clear_stacks();
vm.reset();
vm.set_source(": t3 1 5 0 do 1+ 2 +loop ; t3");
vm.evaluate_input();
assert_eq!(vm.last_error(), None);
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 4);
vm.set_source(": t4 1 6 0 do 1+ 2 +loop ; t4");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 1);
assert_eq!(vm.s_stack().pop(), 4);
}
#[test]
fn test_do_leave_loop() {
let vm = &mut VM::new();
vm.set_source(": t1 leave ; t1");
vm.evaluate_input();
assert_eq!(vm.last_error(), Some(CONTROL_STRUCTURE_MISMATCH));
vm.reset();
vm.clear_stacks();
vm.set_source(": main 1 5 0 do 1+ dup 3 = if drop 88 leave then loop 9 ; main");
vm.evaluate_input();
assert_eq!(vm.last_error(), None);
assert_eq!(vm.s_stack().len(), 2);
assert_eq!(vm.s_stack().pop2(), (88, 9));
}
#[test]
fn test_do_leave_plus_loop() {
let vm = &mut VM::new();
vm.set_source(": main 1 5 0 do 1+ dup 3 = if drop 88 leave then 2 +loop 9 ; main");
vm.evaluate_input();
assert_eq!(vm.last_error(), None);
assert_eq!(vm.s_stack().len(), 2);
assert_eq!(vm.s_stack().pop2(), (88, 9));
}
#[test]
fn test_do_i_loop() {
let vm = &mut VM::new();
vm.set_source(": main 3 0 do i loop ; main");
vm.evaluate_input();
assert_eq!(vm.last_error(), None);
assert_eq!(vm.s_stack().len(), 3);
assert_eq!(vm.s_stack().pop3(), (0, 1, 2));
}
#[test]
fn test_do_i_j_loop() {
let vm = &mut VM::new();
vm.set_source(": main 6 4 do 3 1 do i j * loop loop ; main");
vm.evaluate_input();
assert_eq!(vm.last_error(), None);
assert_eq!(vm.s_stack().len(), 4);
assert_eq!(vm.s_stack().as_slice(), [4, 8, 5, 10]);
}
#[bench]
fn bench_fib(b: &mut Bencher) {
let vm = &mut VM::new();
vm.set_source(": fib dup 2 < if drop 1 else dup 1- recurse swap 2 - recurse + then ;");
vm.evaluate_input();
assert!(vm.last_error().is_none());
vm.set_source(": main 7 fib drop ;");
vm.evaluate_input();
vm.set_source("' main");
vm.evaluate_input();
b.iter(|| {
vm.dup();
vm.execute();
vm.run();
match vm.last_error() {
Some(_) => assert!(false),
None => assert!(true),
};
});
}
#[bench]
fn bench_repeat(b: &mut Bencher) {
let vm = &mut VM::new();
vm.set_source(": bench 0 begin over over > while 1 + repeat drop drop ;");
vm.evaluate_input();
vm.set_source(": main 8000 bench ;");
vm.evaluate_input();
vm.set_source("' main");
vm.evaluate_input();
b.iter(|| {
vm.dup();
vm.execute();
vm.run();
match vm.last_error() {
Some(_) => assert!(false),
None => assert!(true),
};
});
}
#[bench]
fn bench_sieve(b: &mut Bencher) {
let vm = &mut VM::new();
vm.load_core_fth();
if vm.last_error().is_some() {
eprintln!(
"Error {:?} at {:?}",
vm.last_error().unwrap(),
vm.last_token()
);
}
assert_eq!(vm.last_error(), None);
vm.set_source("CREATE FLAGS 8190 ALLOT CREATE EFLAG 1 CELLS ALLOT");
vm.evaluate_input();
assert_eq!(vm.last_error(), None);
vm.set_source(
"
: PRIMES ( -- n ) FLAGS 8190 1 FILL 0 3 EFLAG @ FLAGS
DO I C@
IF DUP I + DUP EFLAG @ <
IF EFLAG @ SWAP
DO 0 I C! DUP +LOOP
ELSE DROP THEN SWAP 1+ SWAP
THEN 2 +
LOOP DROP ;
",
);
vm.evaluate_input();
assert_eq!(vm.last_error(), None);
vm.set_source(
"
: BENCHMARK 0 1 0 DO PRIMES NIP LOOP ;
",
);
vm.evaluate_input();
assert_eq!(vm.last_error(), None);
vm.set_source(
"
: MAIN
FLAGS 8190 + EFLAG !
BENCHMARK DROP
;
",
);
vm.evaluate_input();
assert_eq!(vm.last_error(), None);
vm.set_source("' main");
vm.evaluate_input();
b.iter(|| {
vm.dup();
vm.execute();
vm.run();
match vm.last_error() {
Some(_) => assert!(false),
None => assert!(true),
};
});
}
#[test]
fn test_here_comma_compile_interpret() {
let vm = &mut VM::new();
vm.comma();
vm.check_stacks();
assert_eq!(vm.last_error(), Some(STACK_UNDERFLOW));
vm.reset();
let here = vm.data_space().here();
vm.set_source("here 1 , 2 , ] lit exit [ here");
vm.evaluate_input();
assert!(vm.last_error().is_none());
assert_eq!(vm.s_stack().len(), 2);
let (n, t) = vm.s_stack().pop2();
assert!(!vm.s_stack().underflow());
assert_eq!(t - n, 4 * mem::size_of::<usize>() as isize);
unsafe {
assert_eq!(vm.data_space().get_isize(here + 0), 1);
assert_eq!(vm.data_space().get_isize(here + mem::size_of::<isize>()), 2);
assert_eq!(
vm.data_space()
.get_isize(here + 2 * mem::size_of::<isize>()),
vm.references().idx_lit as isize
);
assert_eq!(
vm.data_space()
.get_isize(here + 3 * mem::size_of::<isize>()),
vm.references().idx_exit as isize
);
}
}
}