Lines
80.77 %
Functions
69.23 %
Branches
46.88 %
use forth::forth_compiler::ForthCompiler;
use forth::stack_machine::GasLimit;
use forth::ForthError;
use std::fs;
use std::{io, io::prelude::*};
pub fn read_init_file(fc: &mut ForthCompiler) {
// check to see if init.forth exists. If so, load definitions..
if fs::metadata("init.forth").is_ok() {
println!("Reading word definitions from init.forth file");
let startup = fs::read_to_string("init.forth");
let _x = match startup {
Ok(s) => Ok(fc.execute_string(&s, GasLimit::Limited(100)).unwrap()),
Err(x) => Err(x),
};
}
fn process_line(fc: &mut ForthCompiler, line: Result<String, io::Error>) -> String {
match line {
Ok(n) => match n.as_str() {
".quit" => {
println!("\n Bye!\n");
std::process::exit(0);
".s" => {
format!("{:?}", fc.sm.st.data_stack)
"XX" => {
// clears the parameter stack
fc.sm.st.data_stack.clear();
format!(" <{}> ok", fc.sm.st.data_stack.len())
// editor commands
"LIST" => {
// lists the contents of the block and sets as the current block (n -- )
"".to_string()
"LOAD" => {
// load (and compile) the contents of the block and set this block as the currnet block (n -- )
"FLUSH" => {
// writes the contents of the block to storage (ie, disk)
"COPY" => {
// copy one block to another (src dest -- )
"WIPE" => {
// clear the contents of the current block
_ => match fc.execute_string(&n, GasLimit::Limited(200)) {
Ok(x) => format!(" {} <{}> ok", x, fc.sm.st.data_stack.len()),
Err(x) => format!("error: {:?}", x),
},
Err(error) => format!("error reading stdin: {error}"),
fn main() -> Result<(), ForthError> {
println!("Forth..");
let mut fc = ForthCompiler::new();
read_init_file(&mut fc);
println!("Type '.quit' to exit..");
for line in io::stdin().lock().lines() {
println!("{}", process_line(&mut fc, line));
Ok(())
#[cfg(test)]
mod tests {
use crate::{process_line, read_init_file};
#[test]
fn test_process_line() {
assert_eq!(
process_line(&mut fc, Ok("2 2 + .".to_string())),
" 4 <0> ok"
);
process_line(&mut fc, Ok("2 2 .".to_string())),
" 2 <1> ok"
assert_eq!(fc.sm.st.data_stack, vec![2]);
assert_eq!(process_line(&mut fc, Ok("XX".to_string())), " <0> ok");
assert_eq!(fc.sm.st.data_stack, vec![]);
fn init_file() {
// let see if some of our init forth file defs work.
fc.execute_string("2 2 + .", GasLimit::Limited(100))
.unwrap(),
"4 "
fc.execute_string("10 PI .", GasLimit::Limited(100))
"314 "
fc.execute_string("100 SQRT .", GasLimit::Limited(100))
"141 "
fc.execute_string("100 E .", GasLimit::Limited(100))
"271 "
fn basic() {
//fc.execute_string("1 IF 1 2 + ELSE 3 4 + THEN", GasLimit::Limited(100))?;
fc.execute_string("0 IF 1 2 + THEN", GasLimit::Limited(100))
.unwrap();
//println!("Contents of Number Stack {:?}", fc.sm.st.data_stack);
assert_eq!(&fc.sm.st.data_stack, &vec![]);
fc.execute_string(": RickTest 1 2 + 3 * ; RickTest", GasLimit::Limited(100))
assert_eq!(&fc.sm.st.data_stack, &vec![9]);
fc.execute_string(": RickTest2 4 5 + 6 * ;", GasLimit::Limited(100))
fc.execute_string(
": RickTest3 RickTest RickTest2 7 + 8 * ;",
GasLimit::Limited(100),
)
fc.execute_string("RickTest3", GasLimit::Limited(100))
assert_eq!(&fc.sm.st.data_stack, &vec![9, 9, 488]);
fc.execute_string("123 321 + 2 *", GasLimit::Limited(100))
assert_eq!(&fc.sm.st.data_stack, &vec![9, 9, 488, 888]);
assert_eq!(&fc.sm.st.data_stack, &vec![9, 9, 488, 888, 888]);
": RickCommand 1234 DUP + 777 ; RickCommand RickCommand",
fc.sm.st.data_stack.push(123);
fc.sm.st.data_stack.push(321);
fc.sm.st.data_stack.push(0);
fc.execute_string("IF + 2 * ELSE + 3 * THEN", GasLimit::Limited(100))
let n = fc.sm.st.data_stack.pop().unwrap();
assert_eq!(n, 1332);