@@ -2,6 +2,7 @@ use std::fs::File;
2
2
use std:: io;
3
3
use std:: io:: BufRead ;
4
4
use std:: io:: BufReader ;
5
+ use std:: io:: Read ;
5
6
use std:: io:: Write ;
6
7
7
8
use crate :: environment:: Environment ;
@@ -11,86 +12,81 @@ use crate::value::Value;
11
12
use std:: rc:: Rc ;
12
13
13
14
use nom:: Err :: Incomplete ;
15
+ use nom:: IResult ;
14
16
use nom:: Needed :: Size ;
15
17
16
- //
17
- // Will possibly just add this to our environment, or turn this into a parallel of clojure.lang.RT
18
- //
19
- pub fn try_eval_file ( environment : & Rc < Environment > , filepath : & str ) -> Result < ( ) , io:: Error > {
20
- let core = File :: open ( filepath) ?;
21
- let reader = BufReader :: new ( core) ;
18
+ pub struct Repl {
19
+ environment : Rc < Environment > ,
20
+ }
21
+ impl Repl {
22
+ pub fn new ( environment : Rc < Environment > ) -> Repl {
23
+ Repl { environment }
24
+ }
22
25
23
- let mut input_buffer = String :: new ( ) ;
26
+ // @TODO reconsider eval's signature; since Value wraps all evaluables, it might make more sense
27
+ // to frame eval as "environment.eval(value)", and then likewise define a
28
+ // 'repl.eval(value)', rather than 'value.eval(environment)'
29
+ pub fn eval ( & self , value : & Value ) -> Value {
30
+ value. eval ( Rc :: clone ( & self . environment ) )
31
+ }
24
32
25
- for line in reader. lines ( ) {
26
- let line = line?;
27
- input_buffer. push_str ( & line) ;
28
- let mut remaining_input = input_buffer. as_str ( ) ;
29
- loop {
30
- let next_read_parse = reader:: try_read ( remaining_input) ;
31
- match next_read_parse {
32
- Ok ( ( _remaining_input, value) ) => {
33
- //print!("{} ",value.eval(Rc::clone(&environment)).to_string_explicit());
34
- value. eval ( Rc :: clone ( & environment) ) ;
35
- remaining_input = _remaining_input;
36
- }
37
- Err ( Incomplete ( Size ( 1 ) ) ) => {
38
- break ;
39
- }
40
- err => {
41
- println ! (
42
- "Error evaluating file {}; {}" ,
43
- filepath,
44
- Value :: Condition ( format!( "Reader Error: {:?}" , err) )
45
- ) ;
46
- input_buffer. clear ( ) ;
47
- // remaining_input = "";
48
- break ;
49
- }
50
- }
51
- }
33
+ // Just wraps reader's read
34
+ pub fn read < R : BufRead > ( reader : & mut R ) -> Value {
35
+ reader:: read ( reader)
52
36
}
37
+ pub fn run ( & self ) {
38
+ let stdin = io:: stdin ( ) ;
39
+ let mut stdin_reader = stdin. lock ( ) ;
53
40
54
- Ok ( ( ) )
55
- }
56
- // @TODO eventually, this will likely be implemented purely in Clojure
57
- /// Starts an entirely new session of Clojure RS
58
- pub fn repl ( ) {
59
- println ! ( "Clojure RS 0.0.1" ) ;
41
+ loop {
42
+ print ! ( "user=> " ) ;
43
+ let _ = io:: stdout ( ) . flush ( ) ;
60
44
61
- let environment = Environment :: clojure_core_environment ( ) ;
62
- let stdin = io:: stdin ( ) ;
45
+ // Read
46
+ let mut next = Repl :: read ( & mut stdin_reader) ;
47
+ // Eval
48
+ let evaled_next = self . eval ( & next) ;
49
+ // Print
50
+ println ! ( "{}" , evaled_next) ;
51
+ // Loop
52
+ }
53
+ }
54
+ //
55
+ // Will possibly just add this to our environment, or turn this into a parallel of clojure.lang.RT
56
+ //
57
+ /// Reads the code in a file sequentially and evaluates the result
58
+ pub fn try_eval_file ( & self , filepath : & str ) -> Result < Value , std:: io:: Error > {
59
+ let core = File :: open ( filepath) ?;
60
+ let mut reader = BufReader :: new ( core) ;
63
61
64
- print ! ( "user=> " ) ;
65
- let _ = io:: stdout ( ) . flush ( ) ;
66
- let mut input_buffer = String :: new ( ) ;
67
- for line in stdin. lock ( ) . lines ( ) {
68
- let line = line. unwrap ( ) ;
69
- input_buffer. push_str ( & line) ;
70
- let mut remaining_input = input_buffer. as_str ( ) ;
62
+ let mut last_val = Repl :: read ( & mut reader) ;
71
63
loop {
72
- let next_read_parse = reader:: try_read ( remaining_input) ;
73
- match next_read_parse {
74
- Ok ( ( _remaining_input, value) ) => {
75
- print ! (
76
- "{} " ,
77
- value. eval( Rc :: clone( & environment) ) . to_string_explicit( )
78
- ) ;
79
- remaining_input = _remaining_input;
80
- }
81
- Err ( Incomplete ( _) ) => {
82
- break ;
83
- }
84
- err => {
85
- print ! ( "{}" , Value :: Condition ( format!( "Reader Error: {:?}" , err) ) ) ;
86
- input_buffer. clear ( ) ;
87
- break ;
64
+ // @TODO this is hardcoded until we refactor Conditions to have keys, so that
65
+ // we can properly identify them
66
+ // @FIXME
67
+ if let Value :: Condition ( cond) = & last_val {
68
+ if cond != "Tried to read empty stream; unexpected EOF" {
69
+ println ! ( "Error reading file: {}" , cond) ;
88
70
}
71
+
72
+ return Ok ( last_val) ;
73
+ }
74
+
75
+ let evaled_last_val = self . eval ( & last_val) ;
76
+
77
+ if let Value :: Condition ( cond) = evaled_last_val {
78
+ println ! ( "{}" , cond) ;
89
79
}
80
+
81
+ last_val = Repl :: read ( & mut reader) ;
82
+ }
83
+ }
84
+ }
85
+
86
+ impl Default for Repl {
87
+ fn default ( ) -> Repl {
88
+ Repl {
89
+ environment : Environment :: clojure_core_environment ( ) ,
90
90
}
91
- input_buffer. clear ( ) ;
92
- println ! ( ) ;
93
- print ! ( "user=> " ) ;
94
- let _ = io:: stdout ( ) . flush ( ) ;
95
91
}
96
92
}
0 commit comments