1
//! `APROPOS` — search the symbol table for names containing a
2
//! substring (case-insensitive), return a sorted quoted list of
3
//! matching symbols. Powers `nomisync-help` completion in emacs and
4
//! the REPL's tab-completion.
5

            
6
use crate::ast::{Expr, WasmType};
7
use crate::compiler::context::CompileContext;
8
use crate::compiler::emit::FunctionEmitter;
9
use crate::compiler::expr::{compile_expr, format_expr};
10
use crate::error::{Error, Result};
11
use crate::runtime::SymbolTable;
12

            
13
use super::compile_static_result_for_stack;
14

            
15
549
pub(super) fn apropos(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
16
549
    if args.len() != 1 {
17
68
        return Err(Error::Arity {
18
68
            name: "APROPOS".to_string(),
19
68
            expected: 1,
20
68
            actual: args.len(),
21
68
        });
22
481
    }
23
481
    let needle = match &args[0] {
24
276
        Expr::String(s) => s.clone(),
25
68
        Expr::Quote(inner) => match inner.as_ref() {
26
            Expr::String(s) => s.clone(),
27
68
            Expr::Symbol(s) => s.clone(),
28
            other => {
29
                return Err(Error::Compile(format!(
30
                    "APROPOS: argument must be a string, got quoted {}",
31
                    format_expr(other)
32
                )));
33
            }
34
        },
35
68
        Expr::Symbol(s) => s.clone(),
36
69
        other => {
37
69
            return Err(Error::Compile(format!(
38
69
                "APROPOS: argument must be a string, got {}",
39
69
                format_expr(other)
40
69
            )));
41
        }
42
    };
43
412
    let needle_uc = needle.to_uppercase();
44
412
    let mut matches: Vec<String> = symbols
45
412
        .iter()
46
90580
        .filter(|(name, _)| name.to_uppercase().contains(&needle_uc))
47
4096
        .map(|(name, _)| name.clone())
48
412
        .collect();
49
412
    matches.sort();
50
412
    let elems = matches.into_iter().map(Expr::Symbol).collect();
51
412
    Ok(Expr::Quote(Box::new(Expr::List(elems))))
52
549
}
53

            
54
408
pub(super) fn compile_apropos(
55
408
    ctx: &mut CompileContext,
56
408
    emit: &mut FunctionEmitter,
57
408
    symbols: &mut SymbolTable,
58
408
    args: &[Expr],
59
408
) -> Result<()> {
60
408
    let result = apropos(symbols, args)?;
61
272
    compile_expr(ctx, emit, symbols, &result)
62
408
}
63

            
64
136
pub(super) fn compile_apropos_for_stack(
65
136
    ctx: &mut CompileContext,
66
136
    emit: &mut FunctionEmitter,
67
136
    symbols: &mut SymbolTable,
68
136
    args: &[Expr],
69
136
) -> Result<WasmType> {
70
136
    let result = apropos(symbols, args)?;
71
136
    compile_static_result_for_stack(ctx, emit, symbols, &result)
72
136
}