1
4
use forth::forth_compiler::ForthCompiler;
2
use forth::stack_machine::GasLimit;
3
use forth::ForthError;
4
use std::fs;
5
use std::{io, io::prelude::*};
6

            
7
1
pub fn read_init_file(fc: &mut ForthCompiler) {
8
    // check to see if init.forth exists.  If so, load definitions..
9
2
    if fs::metadata("init.forth").is_ok() {
10
1
        println!("Reading word definitions from init.forth file");
11
1
        let startup = fs::read_to_string("init.forth");
12
1
        let _x = match startup {
13
1
            Ok(s) => Ok(fc.execute_string(&s, GasLimit::Limited(100)).unwrap()),
14
            Err(x) => Err(x),
15
        };
16
1
    }
17
1
}
18

            
19
3
fn process_line(fc: &mut ForthCompiler, line: Result<String, io::Error>) -> String {
20
3
    match line {
21
3
        Ok(n) => match n.as_str() {
22
3
            ".quit" => {
23
                println!("\n Bye!\n");
24
                std::process::exit(0);
25
            }
26
3
            ".s" => {
27
                format!("{:?}", fc.sm.st.data_stack)
28
            }
29
3
            "XX" => {
30
                // clears the parameter stack
31
1
                fc.sm.st.data_stack.clear();
32
1
                format!("   <{}> ok", fc.sm.st.data_stack.len())
33
            }
34
            // editor commands
35
2
            "LIST" => {
36
                // lists the contents of the block and sets as the current block  (n -- )
37
                "".to_string()
38
            }
39
2
            "LOAD" => {
40
                // load (and compile) the contents of the block and set this block as the currnet block (n -- )
41
                "".to_string()
42
            }
43
2
            "FLUSH" => {
44
                // writes the contents of the block to storage (ie, disk)
45
                "".to_string()
46
            }
47
2
            "COPY" => {
48
                // copy one block to another (src dest -- )
49
                "".to_string()
50
            }
51
2
            "WIPE" => {
52
                // clear the contents of the current block
53
                "".to_string()
54
            }
55
2
            _ => match fc.execute_string(&n, GasLimit::Limited(200)) {
56
2
                Ok(x) => format!(" {}  <{}> ok", x, fc.sm.st.data_stack.len()),
57
                Err(x) => format!("error: {:?}", x),
58
2
            },
59
3
        },
60
        Err(error) => format!("error reading stdin: {error}"),
61
    }
62
3
}
63

            
64
fn main() -> Result<(), ForthError> {
65
    println!("Forth..");
66

            
67
    let mut fc = ForthCompiler::new();
68

            
69
    read_init_file(&mut fc);
70

            
71
    println!("Type '.quit' to exit..");
72

            
73
    for line in io::stdin().lock().lines() {
74
        println!("{}", process_line(&mut fc, line));
75
    }
76

            
77
    Ok(())
78
}
79

            
80
#[cfg(test)]
81
mod tests {
82
    use crate::{process_line, read_init_file};
83
    use forth::forth_compiler::ForthCompiler;
84
    use forth::stack_machine::GasLimit;
85

            
86
    #[test]
87
2
    fn test_process_line() {
88
1
        let mut fc = ForthCompiler::new();
89

            
90
1
        assert_eq!(
91
1
            process_line(&mut fc, Ok("2 2 + .".to_string())),
92
            " 4   <0> ok"
93
        );
94
1
        assert_eq!(
95
1
            process_line(&mut fc, Ok("2 2 .".to_string())),
96
            " 2   <1> ok"
97
        );
98
1
        assert_eq!(fc.sm.st.data_stack, vec![2]);
99
1
        assert_eq!(process_line(&mut fc, Ok("XX".to_string())), "   <0> ok");
100
1
        assert_eq!(fc.sm.st.data_stack, vec![]);
101
2
    }
102

            
103
    #[test]
104
2
    fn init_file() {
105
1
        let mut fc = ForthCompiler::new();
106
1
        read_init_file(&mut fc);
107

            
108
        // let see if some of our init forth file defs work.
109
1
        assert_eq!(
110
1
            fc.execute_string("2 2 + .", GasLimit::Limited(100))
111
                .unwrap(),
112
            "4 "
113
        );
114

            
115
1
        assert_eq!(
116
1
            fc.execute_string("10 PI .", GasLimit::Limited(100))
117
                .unwrap(),
118
            "314 "
119
        );
120
1
        assert_eq!(
121
1
            fc.execute_string("100 SQRT .", GasLimit::Limited(100))
122
                .unwrap(),
123
            "141 "
124
        );
125
1
        assert_eq!(
126
1
            fc.execute_string("100 E .", GasLimit::Limited(100))
127
                .unwrap(),
128
            "271 "
129
        );
130
2
    }
131

            
132
    #[test]
133
2
    fn basic() {
134
1
        let mut fc = ForthCompiler::new();
135

            
136
        //fc.execute_string("1 IF 1 2 + ELSE 3 4 + THEN", GasLimit::Limited(100))?;
137
1
        fc.execute_string("0 IF 1 2 + THEN", GasLimit::Limited(100))
138
1
            .unwrap();
139

            
140
        //println!("Contents of Number Stack {:?}", fc.sm.st.data_stack);
141
1
        assert_eq!(&fc.sm.st.data_stack, &vec![]);
142

            
143
1
        fc.execute_string(": RickTest 1 2 + 3 * ; RickTest", GasLimit::Limited(100))
144
1
            .unwrap();
145

            
146
1
        assert_eq!(&fc.sm.st.data_stack, &vec![9]);
147

            
148
1
        fc.execute_string(": RickTest2 4 5 + 6 * ;", GasLimit::Limited(100))
149
1
            .unwrap();
150

            
151
1
        assert_eq!(&fc.sm.st.data_stack, &vec![9]);
152

            
153
1
        fc.execute_string(
154
            ": RickTest3 RickTest RickTest2 7 + 8 * ;",
155
1
            GasLimit::Limited(100),
156
        )
157
1
        .unwrap();
158

            
159
1
        assert_eq!(&fc.sm.st.data_stack, &vec![9]);
160

            
161
1
        fc.execute_string("RickTest3", GasLimit::Limited(100))
162
1
            .unwrap();
163

            
164
1
        assert_eq!(&fc.sm.st.data_stack, &vec![9, 9, 488]);
165

            
166
1
        fc.execute_string("123 321 + 2 *", GasLimit::Limited(100))
167
1
            .unwrap();
168

            
169
1
        assert_eq!(&fc.sm.st.data_stack, &vec![9, 9, 488, 888]);
170

            
171
1
        fc.execute_string("123 321 + 2 *", GasLimit::Limited(100))
172
1
            .unwrap();
173

            
174
1
        assert_eq!(&fc.sm.st.data_stack, &vec![9, 9, 488, 888, 888]);
175

            
176
1
        fc.execute_string(
177
            ": RickCommand 1234 DUP + 777 ; RickCommand RickCommand",
178
1
            GasLimit::Limited(100),
179
        )
180
1
        .unwrap();
181

            
182
1
        fc.sm.st.data_stack.push(123);
183
1
        fc.sm.st.data_stack.push(321);
184
1
        fc.sm.st.data_stack.push(0);
185
1
        fc.execute_string("IF + 2 * ELSE + 3 * THEN", GasLimit::Limited(100))
186
1
            .unwrap();
187
1
        let n = fc.sm.st.data_stack.pop().unwrap();
188

            
189
1
        assert_eq!(n, 1332);
190
2
    }
191
}