1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use crate::{ansi, ctx};
use cl_lexer::Lexer;
use cl_parser::Parser;
use repline::{error::ReplResult, prebaked::*};

fn clear() {
    println!("{}", ansi::CLEAR_ALL);
    banner()
}

pub fn banner() {
    println!("--- conlang v{} 💪🦈 ---\n", env!("CARGO_PKG_VERSION"))
}

/// Presents a selection interface to the user
pub fn main_menu(ctx: &mut ctx::Context) -> ReplResult<()> {
    banner();
    read_and(ansi::GREEN, "mu>", " ?>", |line| {
        match line.trim() {
            "clear" => clear(),
            "l" | "lex" => lex(ctx)?,
            "f" | "fmt" => fmt(ctx)?,
            "r" | "run" => run(ctx)?,
            "q" | "quit" => return Ok(Response::Break),
            "h" | "help" => println!(
                "Valid commands
    lex     (l): Spin up a lexer, and lex some lines
    fmt     (f): Format the input
    run     (r): Enter the REPL, and evaluate some statements
    help    (h): Print this list
    quit    (q): Exit the program"
            ),
            _ => Err("Unknown command. Type \"help\" for help")?,
        }
        Ok(Response::Accept)
    })
}

pub fn run(ctx: &mut ctx::Context) -> ReplResult<()> {
    read_and(ansi::CYAN, "cl>", " ?>", |line| {
        let code = Parser::new(Lexer::new(line)).stmt()?;

        print!("{}", ansi::OUTPUT);
        match ctx.run(&code) {
            Ok(v) => println!("{}{v}", ansi::RESET),
            Err(e) => println!("{}! > {e}{}", ansi::RED, ansi::RESET),
        }
        Ok(Response::Accept)
    })
}

pub fn lex(_ctx: &mut ctx::Context) -> ReplResult<()> {
    read_and(ansi::BRIGHT_BLUE, "lx>", " ?>", |line| {
        for token in Lexer::new(line) {
            match token {
                Ok(token) => crate::tools::print_token(&token),
                Err(e) => eprintln!("! > {}{e}{}", ansi::RED, ansi::RESET),
            }
        }

        Ok(Response::Accept)
    })
}

pub fn fmt(_ctx: &mut ctx::Context) -> ReplResult<()> {
    read_and(ansi::BRIGHT_MAGENTA, "cl>", " ?>", |line| {
        let mut p = Parser::new(Lexer::new(line));

        match p.stmt() {
            Ok(code) => println!("{}{code}{}", ansi::OUTPUT, ansi::RESET),
            Err(e) => Err(e)?,
        }

        Ok(Response::Accept)
    })
}