@@ -2,6 +2,7 @@ use std::fs::File;
22use std:: io;
33use std:: io:: BufRead ;
44use std:: io:: BufReader ;
5+ use std:: io:: Read ;
56use std:: io:: Write ;
67
78use crate :: environment:: Environment ;
@@ -11,86 +12,81 @@ use crate::value::Value;
1112use std:: rc:: Rc ;
1213
1314use nom:: Err :: Incomplete ;
15+ use nom:: IResult ;
1416use nom:: Needed :: Size ;
1517
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+ }
2225
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+ }
2432
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)
5236 }
37+ pub fn run ( & self ) {
38+ let stdin = io:: stdin ( ) ;
39+ let mut stdin_reader = stdin. lock ( ) ;
5340
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 ( ) ;
6044
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) ;
6361
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) ;
7163 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) ;
8870 }
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) ;
8979 }
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 ( ) ,
9090 }
91- input_buffer. clear ( ) ;
92- println ! ( ) ;
93- print ! ( "user=> " ) ;
94- let _ = io:: stdout ( ) . flush ( ) ;
9591 }
9692}
0 commit comments