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
573
pub(super) fn apropos(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
16
573
    if args.len() != 1 {
17
71
        return Err(Error::Arity {
18
71
            name: "APROPOS".to_string(),
19
71
            expected: 1,
20
71
            actual: args.len(),
21
71
        });
22
502
    }
23
502
    let needle = match &args[0] {
24
288
        Expr::String(s) => s.clone(),
25
71
        Expr::Quote(inner) => match inner.as_ref() {
26
            Expr::String(s) => s.clone(),
27
71
            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
71
        Expr::Symbol(s) => s.clone(),
36
72
        other => {
37
72
            return Err(Error::Compile(format!(
38
72
                "APROPOS: argument must be a string, got {}",
39
72
                format_expr(other)
40
72
            )));
41
        }
42
    };
43
430
    let needle_uc = needle.to_uppercase();
44
430
    let mut matches: Vec<String> = symbols
45
430
        .iter()
46
95250
        .filter(|(name, _)| name.to_uppercase().contains(&needle_uc))
47
4347
        .map(|(name, _)| name.clone())
48
430
        .collect();
49
430
    matches.sort();
50
430
    let elems = matches.into_iter().map(Expr::Symbol).collect();
51
430
    Ok(Expr::Quote(Box::new(Expr::List(elems))))
52
573
}
53

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

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