Skip to main content

rl_lang/interpreter/stdlib/io/
input.rs

1use crate::{
2    interpreter::{evaluator::Evaluator, values::Value},
3    utils::{errors::Error, span::Span},
4};
5use std::io::{self, Write};
6
7fn input(prompt: Option<Value>, eval: &mut Evaluator, span: Span) -> Result<Value, Error> {
8    match prompt {
9        None => read_line(eval, span),
10        Some(p) => {
11            let prompt = match p {
12                Value::Integer(i) => i.to_string(),
13                Value::Float(f) => f.to_string(),
14                Value::String(s) => s,
15                Value::Char(c) => c.to_string(),
16                Value::Bool(b) => b.to_string(),
17                Value::Null => "null".to_string(),
18                _ => "".to_string(),
19            };
20            print!("{}", prompt);
21            io::stdout().flush().ok();
22            read_line(eval, span)
23        }
24    }
25}
26
27fn read_line(eval: &mut Evaluator, span: Span) -> Result<Value, Error> {
28    let mut input = String::new();
29    io::stdin()
30        .read_line(&mut input)
31        .map_err(|e| eval.err(format!("read(): failed to read line: {}", e), span))?;
32    Ok(Value::String(input.trim().to_string()))
33}
34
35pub fn std_read(eval: &mut Evaluator, args: Vec<Value>, span: Span) -> Result<Value, Error> {
36    let len = args.len();
37    let mut args = args.into_iter();
38
39    match len {
40        0 => input(None, eval, span),
41        1 => input(args.next(), eval, span),
42        n => Err(eval.err(
43            format!("read() expects 0 or 1 argument(s), got {}", n),
44            span,
45        )),
46    }
47}
48
49// reads input then parses to integer if possible otherwise error
50pub fn std_read_int(eval: &mut Evaluator, args: Vec<Value>, span: Span) -> Result<Value, Error> {
51    let len = args.len();
52    let mut args = args.into_iter();
53
54    let value = match len {
55        0 => input(None, eval, span),
56        1 => input(args.next(), eval, span),
57        n => Err(eval.err(
58            format!("read_int() expects 0 or 1 argument(s), got {}", n),
59            span,
60        )),
61    }?;
62
63    match value {
64        Value::String(s) => s.parse::<i64>().map(Value::Integer).map_err(|_| {
65            eval.err(
66                format!("read_int(): \"{}\" is not a valid integer", s),
67                span,
68            )
69        }),
70        // those unreachable btw
71        Value::Integer(i) => Ok(Value::Integer(i)),
72        Value::Float(f) => Ok(Value::Integer(f as i64)),
73        other => Err(eval.err(
74            format!(
75                "read_int(): found unsupported type from input, got {}",
76                other.type_name()
77            ),
78            span,
79        )),
80    }
81}
82
83// reads the input then parses the string into float if possible or error
84pub fn std_read_float(eval: &mut Evaluator, args: Vec<Value>, span: Span) -> Result<Value, Error> {
85    let len = args.len();
86    let mut args = args.into_iter();
87
88    let value = match len {
89        0 => input(None, eval, span),
90        1 => input(args.next(), eval, span),
91        n => Err(eval.err(
92            format!("read_float() expects 0 or 1 argument(s), got {}", n),
93            span,
94        )),
95    }?;
96
97    match value {
98        Value::String(s) => s.parse::<f64>().map(Value::Float).map_err(|_| {
99            eval.err(
100                format!("read_float(): \"{}\" is not a valid float", s),
101                span,
102            )
103        }),
104        // those are un----reachable!! might change read_line() or remove them
105        Value::Integer(i) => Ok(Value::Float(i as f64)),
106        Value::Float(f) => Ok(Value::Float(f)),
107        other => Err(eval.err(
108            format!(
109                "read_float(): found unsupported type from input, got {}",
110                other.type_name()
111            ),
112            span,
113        )),
114    }
115}