use super::{P_DO_RT, P_LOOP_RT};
use crate::types::{Cell, Entry, Instruction};
impl super::VM {
pub(crate) fn prim_colon(&mut self) {
if let Some(name) = self.next_word() {
self.compiling = true;
self.current_def = Some(Entry {
name: name.to_uppercase(),
immediate: false,
hidden: false,
body: Vec::new(),
});
} else {
self.emit_str("error: expected word name after ':'\n");
}
}
pub(crate) fn prim_semicolon(&mut self) {
if let Some(def) = self.current_def.take() {
self.dictionary.push(def);
self.compiling = false;
} else {
self.emit_str("error: ; without matching ':'\n");
}
}
pub(crate) fn prim_create(&mut self) {
if let Some(name) = self.next_word() {
let addr = self.here as Cell;
self.dictionary.push(Entry {
name: name.to_uppercase(),
immediate: false,
hidden: false,
body: vec![Instruction::Literal(addr)],
});
} else {
self.emit_str("error: expected word name after CREATE\n");
}
}
pub(crate) fn prim_does(&mut self) {
}
pub(crate) fn prim_variable(&mut self) {
if let Some(name) = self.next_word() {
let addr = self.here;
self.here += 1;
self.dictionary.push(Entry {
name: name.to_uppercase(),
immediate: false,
hidden: false,
body: vec![Instruction::Literal(addr as Cell)],
});
} else {
self.emit_str("error: expected word name after VARIABLE\n");
}
}
pub(crate) fn prim_constant(&mut self) {
if let Some(name) = self.next_word() {
let val = self.pop();
self.dictionary.push(Entry {
name: name.to_uppercase(),
immediate: false,
hidden: false,
body: vec![Instruction::Literal(val)],
});
} else {
self.emit_str("error: expected word name after CONSTANT\n");
}
}
pub(crate) fn prim_if(&mut self) {
if !self.compiling && self.current_def.is_none() {
self.compiling = true;
self.current_def = Some(Entry {
name: String::new(), immediate: false,
hidden: true,
body: Vec::new(),
});
self.anon_depth = 0;
}
self.anon_depth += 1;
if let Some(ref mut def) = self.current_def {
let fixup = def.body.len() as Cell;
self.rstack.push(fixup);
def.body.push(Instruction::BranchIfZero(0));
}
}
pub(crate) fn prim_else(&mut self) {
let if_fixup = self.rstack.pop().unwrap_or(0) as usize;
if let Some(ref mut def) = self.current_def {
let here = def.body.len();
let offset = (here as i64 + 1) - if_fixup as i64;
def.body[if_fixup] = Instruction::BranchIfZero(offset);
def.body.push(Instruction::Branch(0));
self.rstack.push(here as Cell);
}
}
pub(crate) fn prim_then(&mut self) {
let fixup = self.rstack.pop().unwrap_or(0) as usize;
if let Some(ref mut def) = self.current_def {
let here = def.body.len();
let offset = here as i64 - fixup as i64;
match def.body[fixup] {
Instruction::BranchIfZero(_) => {
def.body[fixup] = Instruction::BranchIfZero(offset);
}
Instruction::Branch(_) => {
def.body[fixup] = Instruction::Branch(offset);
}
_ => {}
}
self.anon_depth -= 1;
if def.name.is_empty() && self.anon_depth <= 0 {
let body = def.body.clone();
self.current_def = None;
self.compiling = false;
self.anon_depth = 0;
self.execute_body(&body);
}
}
}
pub(crate) fn prim_do(&mut self) {
if !self.compiling && self.current_def.is_none() {
self.compiling = true;
self.current_def = Some(Entry {
name: String::new(),
immediate: false,
hidden: true,
body: Vec::new(),
});
self.anon_depth = 0;
}
self.anon_depth += 1;
if let Some(ref mut def) = self.current_def {
def.body.push(Instruction::Primitive(P_DO_RT));
let loop_start = def.body.len() as Cell;
self.rstack.push(loop_start);
}
}
pub(crate) fn prim_loop(&mut self) {
let loop_start = self.rstack.pop().unwrap_or(0);
if let Some(ref mut def) = self.current_def {
def.body.push(Instruction::Primitive(P_LOOP_RT));
let here = def.body.len();
let offset = loop_start - here as i64;
def.body.push(Instruction::BranchIfZero(offset));
self.anon_depth -= 1;
if def.name.is_empty() && self.anon_depth <= 0 {
let body = def.body.clone();
self.current_def = None;
self.compiling = false;
self.anon_depth = 0;
self.execute_body(&body);
}
}
}
pub(crate) fn prim_begin(&mut self) {
if let Some(ref def) = self.current_def {
let here = def.body.len() as Cell;
self.rstack.push(here);
}
}
pub(crate) fn prim_until(&mut self) {
let begin_addr = self.rstack.pop().unwrap_or(0);
if let Some(ref mut def) = self.current_def {
let here = def.body.len();
let offset = begin_addr - here as i64;
def.body.push(Instruction::BranchIfZero(offset));
}
}
pub(crate) fn prim_while(&mut self) {
if let Some(ref mut def) = self.current_def {
let fixup = def.body.len() as Cell;
self.rstack.push(fixup);
def.body.push(Instruction::BranchIfZero(0));
}
}
pub(crate) fn prim_repeat(&mut self) {
let while_fixup = self.rstack.pop().unwrap_or(0) as usize;
let begin_addr = self.rstack.pop().unwrap_or(0);
if let Some(ref mut def) = self.current_def {
let here = def.body.len();
let offset = begin_addr - here as i64;
def.body.push(Instruction::Branch(offset));
let after = def.body.len();
let while_offset = after as i64 - while_fixup as i64;
def.body[while_fixup] = Instruction::BranchIfZero(while_offset);
}
}
pub(crate) fn rt_do(&mut self) {
let index = self.pop();
let limit = self.pop();
self.rstack.push(limit);
self.rstack.push(index);
}
pub(crate) fn rt_loop(&mut self) {
let index = self.rpop() + 1;
let limit = *self.rstack.last().unwrap_or(&0);
if index >= limit {
self.rpop(); self.stack.push(-1); } else {
self.rstack.push(index);
self.stack.push(0); }
}
pub(crate) fn prim_dot_quote(&mut self) {
let s = self.parse_until('"');
if self.compiling {
if let Some(ref mut def) = self.current_def {
def.body.push(Instruction::StringLit(s));
}
} else {
self.emit_str(&s);
}
}
pub(crate) fn prim_paren(&mut self) {
self.parse_until(')');
}
pub(crate) fn prim_backslash(&mut self) {
self.input_pos = self.input_buffer.len();
}
pub fn load_prelude(&mut self) {
let prelude = include_str!("../prelude.fs");
let saved_silent = self.silent;
self.silent = true;
for line in prelude.lines() {
self.interpret_line(line);
}
self.silent = saved_silent;
}
}