narju/repl/
commands.rs

1//! REPL command implementations (:help, :env, :ctx, :load, :reset).
2
3use crate::core::Val;
4use crate::eval::{display, EvalCtx};
5
6use crate::colours::*;
7use super::TopLevel;
8
9/// A one-word kind tag for a value, shown next to each REPL result.
10pub fn type_of(v: &Val) -> &'static str {
11    match v {
12        Val::Cst(_) => "Int",
13        Val::Nil => "Nil",
14        Val::Sym(_) => "Sym",
15        Val::Tup(_, _) => "Cons",
16        Val::Clo(_, _) => "Clo",
17        Val::Code(_) => "Code",
18        Val::Cell(_) => "Cell",
19    }
20}
21
22/// Print one `name : Kind value` line for `:env`, truncating long
23/// values so a big code tree cannot flood the listing.
24pub fn display_binding(name: &str, val: &Val) {
25    let ty = type_of(val);
26    let repr = display(val);
27    let repr = if repr.len() > 60 {
28        format!("{}…", &repr[..60])
29    } else {
30        repr
31    };
32    println!("  {ROSE}{name}{RESET} {DIM}:{RESET} {THORN}{ty}{RESET}  {PETAL}{repr}{RESET}");
33}
34
35/// `:help` — list the REPL commands.
36pub fn cmd_help() {
37    println!();
38    println!("  {BOLD}{ROSE}narju REPL commands{RESET}");
39    println!();
40    println!("  {ROSE}:help{RESET}              this message");
41    println!("  {ROSE}:q{RESET}  {ROSE}:quit{RESET}        exit");
42    println!("  {ROSE}:env{RESET}               list all bindings");
43    println!("  {ROSE}:env{RESET} {PETAL}<name>{RESET}       inspect a single binding");
44    println!("  {ROSE}:ctx{RESET}               show staging context state");
45    println!("  {ROSE}:load{RESET} {PETAL}<file>{RESET}      load a .naj file");
46    println!("  {ROSE}:reset{RESET}             clear environment and staging context");
47    println!();
48    println!(
49        "  {DIM}Multi-line input: open a '(' and press Enter - narju waits for closing ')'.{RESET}"
50    );
51    println!("  {DIM}History: up/down arrows. Alt-P/Alt-N for search.{RESET}");
52    println!();
53}
54
55/// `:env` — list every binding in `top`, or inspect the single binding
56/// `name` when given.
57pub fn cmd_env(top: &TopLevel, name: Option<&str>) {
58    if let Some(name) = name {
59        match top.names.iter().position(|n| n == name) {
60            Some(i) => display_binding(name, &top.env[i]),
61            None => eprintln!("  {WARN}unbound:{RESET} {name}"),
62        }
63        return;
64    }
65    if top.names.is_empty() {
66        println!("  {THORN}(empty environment){RESET}");
67        return;
68    }
69    println!();
70    println!("  {BOLD}{DIM}name                type   value{RESET}");
71    println!("  {DIM}────────────────────────────────────────────────────────────{RESET}");
72    for (name, val) in top.names.iter().zip(top.env.iter()) {
73        display_binding(name, val);
74    }
75    println!(
76        "  {DIM}({} binding{}){RESET}",
77        top.names.len(),
78        if top.names.len() == 1 { "" } else { "s" }
79    );
80    println!();
81}
82
83/// `:ctx` — show the staging context's counters: tower level, fresh
84/// variable counter, pending ANF block depth, and memoised closure
85/// count.
86pub fn cmd_ctx(ctx: &EvalCtx) {
87    println!();
88    println!("  {BOLD}{DIM}staging context{RESET}");
89    println!(
90        "  {ROSE}level{RESET}  {BLOOM}{}{RESET}   {DIM}tower depth (run nesting){RESET}",
91        ctx.level
92    );
93    println!(
94        "  {ROSE}fresh{RESET}  {PETAL}{}{RESET}   {DIM}next de Bruijn level{RESET}",
95        ctx.fresh
96    );
97    println!(
98        "  {ROSE}block{RESET}  {PETAL}{}{RESET}   {DIM}pending ANF lets{RESET}",
99        ctx.block.len()
100    );
101    println!(
102        "  {ROSE}fun  {RESET}  {PETAL}{}{RESET}   {DIM}memoised closures{RESET}",
103        ctx.fun_len()
104    );
105    println!();
106}