Skip to content

Commit d82ca34

Browse files
committed
Merge branch 'feature/read-line' [#40]
2 parents 7aec297 + fb3e9e8 commit d82ca34

File tree

11 files changed

+202
-20
lines changed

11 files changed

+202
-20
lines changed

src/clojure/core.clj

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
(def *flush-on-newline* true)
2+
(def *print-readably* true)
3+
14
(def list (fn [& ls] ls))
25

36
(defmacro defn [name args & body]
@@ -8,19 +11,38 @@
811
(defn apply [f args]
912
(lexical-eval (concat (list f) args)))
1013

11-
(defn println [& more]
14+
(defn newline
15+
[]
16+
(system-newline))
17+
18+
(defn flush
19+
[]
20+
(flush-stdout))
21+
22+
(defn pr [& more]
1223
(print-string (apply str more)))
1324

25+
(defn prn [& more]
26+
(apply pr more)
27+
(newline)
28+
(flush))
29+
30+
(defn print [& more]
31+
(apply pr more))
32+
33+
(defn println [& more]
34+
(apply prn more))
35+
1436
(defn inc [x]
1537
(+ x 1))
1638

1739
(defn dec [x]
1840
(- x 1))
1941

2042
(defmacro time [expr]
21-
(list (quote let) [(quote start) (quote (System_nanotime)) (quote ret) expr]
43+
(list (quote let) [(quote start) (quote (System/nanoTime)) (quote ret) expr]
2244
(quote (do
23-
(println (str "Elapsed time: " (_slash_ (- (System_nanotime) start) 1000000.0) " msecs"))
45+
(println (str "Elapsed time: " (_slash_ (- (System/nanoTime) start) 1000000.0) " msecs"))
2446
ret))))
2547

2648
(defn slurp [f & opts]

src/clojure_std.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
pub(crate) mod thread;
2-
pub(crate) mod time;
1+
pub (crate) mod thread;
2+
pub (crate) mod time;
3+
pub (crate) mod env;

src/clojure_std/env.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use crate::error_message;
2+
use crate::ifn::IFn;
3+
use crate::value::{ToValue, Value};
4+
use std::rc::Rc;
5+
6+
use std::env;
7+
use crate::type_tag::TypeTag;
8+
9+
/// provides a function to return env variables
10+
/// similair to Clojure (System/getenv [key])
11+
#[derive(Debug, Clone)]
12+
pub struct GetEnvFn {}
13+
impl ToValue for GetEnvFn {
14+
fn to_value(&self) -> Value {
15+
Value::IFn(Rc::new(self.clone()))
16+
}
17+
}
18+
19+
impl IFn for GetEnvFn {
20+
fn invoke(&self, args: Vec<Rc<Value>>) -> Value {
21+
if args.len() == 1 {
22+
match args.get(0).unwrap().to_value() {
23+
Value::String(key) => {
24+
match env::var(key) {
25+
Ok(val) => Value::String(val),
26+
Err(_) => Value::Nil
27+
}
28+
}
29+
_a => error_message::type_mismatch(TypeTag::String, &_a)
30+
}
31+
} else {
32+
return error_message::wrong_arg_count(1, args.len());
33+
}
34+
}
35+
}

src/environment.rs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,10 @@ impl Environment {
189189
let nth_fn = rust_core::NthFn {};
190190
let do_macro = rust_core::DoMacro {};
191191
let concat_fn = rust_core::ConcatFn {};
192+
let flush_stdout_fn = rust_core::FlushStdoutFn {};
193+
let system_newline_fn = rust_core::SystemNewlineFn {};
192194
let print_string_fn = rust_core::PrintStringFn {};
195+
let read_line_fn = rust_core::ReadLineFn {};
193196
let assoc_fn = rust_core::AssocFn {};
194197

195198
// rust implementations of core functions
@@ -198,6 +201,7 @@ impl Environment {
198201
// clojure.std functions
199202
let thread_sleep_fn = clojure_std::thread::SleepFn {};
200203
let nanotime_fn = clojure_std::time::NanoTimeFn {};
204+
let get_env_fn = clojure_std::env::GetEnvFn {};
201205

202206
let get_fn = rust_core::GetFn {};
203207
let map_fn = rust_core::MapFn {};
@@ -249,13 +253,24 @@ impl Environment {
249253
environment.insert(Symbol::intern("defmacro"), defmacro_macro.to_rc_value());
250254
environment.insert(Symbol::intern("eval"), eval_fn.to_rc_value());
251255

252-
// Thread namespace TODO / instead of _
253-
environment.insert(
254-
Symbol::intern("Thread_sleep"),
255-
thread_sleep_fn.to_rc_value(),
256-
);
257-
258-
environment.insert(Symbol::intern("System_nanotime"), nanotime_fn.to_rc_value());
256+
// Thread namespace
257+
environment.insert_into_namespace(
258+
&Symbol::intern("Thread"),
259+
Symbol::intern("sleep"),
260+
thread_sleep_fn.to_rc_value()
261+
);
262+
263+
// System namespace
264+
environment.insert_into_namespace(
265+
&Symbol::intern("System"),
266+
Symbol::intern("nanoTime"),
267+
nanotime_fn.to_rc_value()
268+
);
269+
environment.insert_into_namespace(
270+
&Symbol::intern("System"),
271+
Symbol::intern("getenv"),
272+
get_env_fn.to_rc_value()
273+
);
259274

260275
// core.clj wraps calls to the rust implementations
261276
// @TODO add this to clojure.rs.core namespace as clojure.rs.core/slurp
@@ -357,10 +372,21 @@ impl Environment {
357372
environment.insert(Symbol::intern("assoc"), assoc_fn.to_rc_value());
358373
environment.insert(Symbol::intern("get"), get_fn.to_rc_value());
359374
environment.insert(Symbol::intern("concat"), concat_fn.to_rc_value());
375+
376+
// input and output
377+
environment.insert(
378+
Symbol::intern("system-newline"),
379+
system_newline_fn.to_rc_value(),
380+
);
381+
environment.insert(
382+
Symbol::intern("flush-stdout"),
383+
flush_stdout_fn.to_rc_value(),
384+
);
360385
environment.insert(
361386
Symbol::intern("print-string"),
362387
print_string_fn.to_rc_value(),
363388
);
389+
environment.insert(Symbol::intern("read-line"), read_line_fn.to_rc_value());
364390

365391
//
366392
// Read in clojure.core

src/repl.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,18 @@ impl Repl {
3131
}
3232
pub fn run(&self) {
3333
let stdin = io::stdin();
34-
let mut stdin_reader = stdin.lock();
3534

3635
loop {
3736
print!("{}=> ", self.environment.get_current_namespace_name());
3837
let _ = io::stdout().flush();
3938

40-
// Read
41-
let next = Repl::read(&mut stdin_reader);
39+
let next = {
40+
let mut stdin_reader = stdin.lock();
41+
// Read
42+
Repl::read(&mut stdin_reader)
43+
// Release stdin.lock
44+
};
45+
4246
// Eval
4347
let evaled_next = self.eval(&next);
4448
// Print

src/rust_core.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,18 @@ pub use self::get::*;
4747
pub(crate) mod map;
4848
pub use self::map::*;
4949

50-
// input and outputy
50+
// input and output
51+
pub(crate) mod system_newline;
52+
pub use self::system_newline::*;
53+
pub(crate) mod flush_stdout;
54+
pub use self::flush_stdout::*;
5155
pub(crate) mod print_string;
5256
pub use self::print_string::*;
5357
pub(crate) mod string_print;
5458
pub use self::string_print::*;
59+
pub(crate) mod read_line;
60+
pub use self::read_line::*;
61+
5562

5663
// other
5764
pub(crate) mod slurp;

src/rust_core/_divide_.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ mod tests {
7171
use std::rc::Rc;
7272

7373
#[test]
74-
fn divide_without_arguments_returns_one() {
74+
fn divide_without_arguments_returns_error() {
7575
let divide = DivideFn {};
7676
let args = vec![];
7777
assert_eq!(

src/rust_core/flush_stdout.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use crate::ifn::IFn;
2+
use crate::value::{Value, ToValue, Evaluable};
3+
use std::rc::Rc;
4+
5+
use std::io;
6+
7+
use crate::error_message;
8+
use nom::lib::std::convert::TryFrom;
9+
use std::io::{Read, Write};
10+
11+
/// Read a line from stdin TODO: should be aware of *in*
12+
/// (defn read-line [])
13+
#[derive(Debug, Clone)]
14+
pub struct FlushStdoutFn {}
15+
impl ToValue for FlushStdoutFn {
16+
fn to_value(&self) -> Value {
17+
Value::IFn(Rc::new(self.clone()))
18+
}
19+
}
20+
impl IFn for FlushStdoutFn {
21+
fn invoke(&self, args: Vec<Rc<Value>>) -> Value {
22+
if args.len() != 0 {
23+
return error_message::wrong_arg_count(0, args.len())
24+
}
25+
io::stdout().flush();
26+
Value::Nil
27+
}
28+
}

src/rust_core/print_string.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use std::rc::Rc;
44

55
use crate::error_message;
66

7-
/// Primitive printing function;
8-
/// (defn print-string [string] .. prints single string .. )
7+
/// Primitive printing function; TODO: should be aware of *out*
8+
/// (defn print-string [string] .. prints single string without linebreak.. )
99
#[derive(Debug, Clone)]
1010
pub struct PrintStringFn {}
1111
impl ToValue for PrintStringFn {
@@ -18,7 +18,7 @@ impl IFn for PrintStringFn {
1818
if args.len() != 1 {
1919
return error_message::wrong_arg_count(1, args.len());
2020
}
21-
println!("{}", args.get(0).unwrap().to_string());
21+
print!("{}", args.get(0).unwrap().to_string());
2222
Value::Nil
2323
}
2424
}

src/rust_core/read_line.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use crate::ifn::IFn;
2+
use crate::value::{Value, ToValue, Evaluable};
3+
use std::rc::Rc;
4+
5+
use std::io;
6+
7+
use crate::error_message;
8+
use nom::lib::std::convert::TryFrom;
9+
use std::io::{Read, Write};
10+
11+
/// Read a line from stdin TODO: should be aware of *in*
12+
/// (defn read-line [])
13+
#[derive(Debug, Clone)]
14+
pub struct ReadLineFn {}
15+
impl ToValue for ReadLineFn {
16+
fn to_value(&self) -> Value {
17+
Value::IFn(Rc::new(self.clone()))
18+
}
19+
}
20+
impl IFn for ReadLineFn {
21+
fn invoke(&self, args: Vec<Rc<Value>>) -> Value {
22+
if args.len() != 0 {
23+
return error_message::wrong_arg_count(0, args.len())
24+
}
25+
let mut input = String::new();
26+
match io::stdin().read_line(&mut input) {
27+
Ok(_) => {
28+
input.pop();
29+
Value::String(input)
30+
},
31+
Err(error) => error_message::generic_err(Box::try_from(error).unwrap())
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)