kure2_cli/
lib.rs

1use std::{io, ops};
2
3use kure2::lang::State;
4
5use crate::commands::Node;
6
7pub mod commands;
8pub mod repl_helper;
9
10const WELCOME_MESSAGE: &str = "Welcome to the kure2-rs REPL! Type '.help' for assistance.";
11
12pub struct Repl {
13    pub commands: Node,
14    pub state: State,
15}
16
17impl Repl {
18    pub fn new() -> Self {
19        Self {
20            commands: Node::root(),
21            state: State::new(),
22        }
23    }
24
25    pub fn welcome(&self, mut out: impl io::Write) -> io::Result<()> {
26        writeln!(out, "{WELCOME_MESSAGE}")?;
27        Ok(())
28    }
29
30    pub fn process_input(
31        &mut self,
32        line: &str,
33        mut out: impl io::Write,
34    ) -> io::Result<ops::ControlFlow<()>> {
35        let line = line.trim();
36        if line.is_empty() || line.starts_with('{') {
37            Ok(ops::ControlFlow::Continue(()))
38        } else if line.starts_with('.') {
39            self.process_command(line, &mut out)
40        } else if let Some((var, expr)) = line.split_once('=') {
41            let result = self.state.assign(var.trim(), expr.trim());
42            match result {
43                Ok(()) => {}
44                Err(e) => writeln!(out, "Error: {e}")?,
45            }
46
47            Ok(ops::ControlFlow::Continue(()))
48        } else {
49            let result = self.state.exec(line);
50            match result {
51                Ok(value) => {
52                    // Relation::display already adds a newline.
53                    write!(out, "{}", value.display("<expr>"))?;
54                }
55                Err(e) => writeln!(out, "Error: {e}")?,
56            }
57
58            Ok(ops::ControlFlow::Continue(()))
59        }
60    }
61
62    fn process_command(
63        &mut self,
64        command: &str,
65        mut out: impl io::Write,
66    ) -> io::Result<ops::ControlFlow<()>> {
67        let args = command.split_whitespace().collect::<Vec<_>>();
68
69        let Some(node) = self.commands.traverse(&args) else {
70            writeln!(out, "Unknown command or invalid syntax")?;
71            return Ok(ops::ControlFlow::Continue(()));
72        };
73        let Some(func) = &node.func else {
74            writeln!(out, "Incomplete command")?;
75            return Ok(ops::ControlFlow::Continue(()));
76        };
77
78        func(&mut self.state, &mut out, &args)
79    }
80}