cl_repl/
menu.rs

1use crate::{ansi, ctx};
2use cl_ast::Stmt;
3use cl_interpret::convalue::ConValue;
4use cl_lexer::Lexer;
5use cl_parser::Parser;
6use repline::{error::ReplResult, prebaked::*};
7
8pub fn clear() {
9    print!("{}", ansi::CLEAR_ALL);
10    banner()
11}
12
13pub fn banner() {
14    println!("--- conlang v{} 💪🦈 ---", env!("CARGO_PKG_VERSION"))
15}
16
17/// Presents a selection interface to the user
18pub fn main_menu(ctx: &mut ctx::Context) -> ReplResult<()> {
19    banner();
20    run(ctx)?;
21    read_and(ansi::GREEN, "mu>", " ?>", |line| {
22        match line.trim() {
23            "clear" => clear(),
24            "l" | "lex" => lex(ctx)?,
25            "f" | "fmt" => fmt(ctx)?,
26            "r" | "run" => run(ctx)?,
27            "q" | "quit" => return Ok(Response::Break),
28            "h" | "help" => println!(
29                "Valid commands
30    lex     (l): Spin up a lexer, and lex some lines
31    fmt     (f): Format the input
32    run     (r): Enter the REPL, and evaluate some statements
33    help    (h): Print this list
34    quit    (q): Exit the program"
35            ),
36            _ => Err("Unknown command. Type \"help\" for help")?,
37        }
38        Ok(Response::Accept)
39    })
40}
41
42pub fn run(ctx: &mut ctx::Context) -> ReplResult<()> {
43    use cl_ast::ast_visitor::Fold;
44    use cl_parser::inliner::ModuleInliner;
45
46    read_and(ansi::CYAN, "cl>", " ?>", |line| {
47        if line.trim().is_empty() {
48            return Ok(Response::Deny);
49        }
50        let code = Parser::new("", Lexer::new(line)).parse::<Stmt>()?;
51        let code = ModuleInliner::new(".").fold_stmt(code);
52
53        print!("{}", ansi::OUTPUT);
54        match ctx.run(&code) {
55            Ok(ConValue::Empty) => print!("{}", ansi::RESET),
56            Ok(v) => println!("{}{v}", ansi::RESET),
57            Err(e) => println!("{}! > {e}{}", ansi::RED, ansi::RESET),
58        }
59        Ok(Response::Accept)
60    })
61}
62
63pub fn lex(_ctx: &mut ctx::Context) -> ReplResult<()> {
64    read_and(ansi::BRIGHT_BLUE, "lx>", " ?>", |line| {
65        for token in Lexer::new(line) {
66            match token {
67                Ok(token) => crate::tools::print_token(&token),
68                Err(e) => eprintln!("! > {}{e}{}", ansi::RED, ansi::RESET),
69            }
70        }
71
72        Ok(Response::Accept)
73    })
74}
75
76pub fn fmt(_ctx: &mut ctx::Context) -> ReplResult<()> {
77    read_and(ansi::BRIGHT_MAGENTA, "cl>", " ?>", |line| {
78        let mut p = Parser::new("", Lexer::new(line));
79
80        match p.parse::<Stmt>() {
81            Ok(code) => println!("{}{code}{}", ansi::OUTPUT, ansi::RESET),
82            Err(e) => Err(e)?,
83        }
84
85        Ok(Response::Accept)
86    })
87}