uni_core/primitives/
help.rs1use crate::compat::{Rc, format, ToString};
2use crate::interpreter::Interpreter;
3use crate::value::{RuntimeError, Value};
4
5const IF_DOC: &str = "Conditional branching. Usage: condition true-branch false-branch if";
6const EXEC_DOC: &str =
7 "Execute the value at the top of the stack. Lists run as code, other values execute directly.";
8const QUIT_DOC: &str = "Exit the REPL or terminate script execution. Usage: quit";
9
10pub fn help_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
11 let word = interp.pop()?;
12 let atom = match word {
13 Value::Atom(name) => name,
14 _ => {
15 return Err(RuntimeError::TypeError(
16 "help expects an atom (use 'word help)".to_string(),
17 ));
18 }
19 };
20
21 let (doc, is_executable) = if atom.as_ref() == "if" {
22 (Some(Rc::<str>::from(IF_DOC)), true)
23 } else if atom.as_ref() == "exec" {
24 (Some(Rc::<str>::from(EXEC_DOC)), true)
25 } else if atom.as_ref() == "quit" {
26 (Some(Rc::<str>::from(QUIT_DOC)), true)
27 } else {
28 let entry = interp
29 .dictionary
30 .get(&atom)
31 .ok_or_else(|| RuntimeError::UndefinedWord(atom.to_string()))?;
32 (entry.doc.clone(), entry.is_executable)
33 };
34
35 let name_str = atom.to_string();
36
37 if let Some(doc_text) = doc {
38 if doc_text.trim().is_empty() {
39 let output = format!("{}: documentation is empty", name_str);
40 let _ = interp.writeln(&output);
41 } else {
42 let output = format!("{}:", name_str);
45 let _ = interp.writeln(&output);
46
47 for line in doc_text.split('\n') {
49 let _ = interp.writeln(line);
50 }
51 }
52 } else {
53 let kind = if is_executable { "word" } else { "constant" };
54 let output = format!("{} ({}) has no documentation yet", name_str, kind);
55 let _ = interp.writeln(&output);
56 }
57
58 Ok(())
59}