Skip to main content

seqc/
builtins.rs

1//! Built-in word signatures for Seq
2//!
3//! Defines the stack effects for all runtime built-in operations.
4//!
5//! The signatures and docs are split across per-category sub-modules under
6//! `builtins/`, each exposing an `add_signatures(&mut sigs)` and an
7//! `add_docs(&mut docs)` helper. This file composes them into the public
8//! `builtin_signatures()` and `builtin_docs()` maps.
9
10use crate::types::Effect;
11use std::collections::HashMap;
12use std::sync::LazyLock;
13
14mod adt;
15mod arith;
16mod callable;
17mod concurrency;
18mod diagnostics;
19mod dns;
20mod float;
21mod fs;
22mod http;
23mod io;
24mod list;
25mod macros;
26mod map;
27mod os;
28mod stack;
29mod tcp;
30mod text;
31mod tls;
32mod udp;
33
34#[cfg(test)]
35mod tests;
36
37type AddSigsFn = fn(&mut HashMap<String, Effect>);
38type AddDocsFn = fn(&mut HashMap<&'static str, &'static str>);
39
40/// Single source of truth for the built-in category sub-modules.
41///
42/// Adding a new sub-module requires exactly one row here; the signature map,
43/// the doc map, and `builtin_categories()` all iterate over this list, so
44/// they cannot drift apart.
45const CATEGORIES: &[(&str, AddSigsFn, AddDocsFn)] = &[
46    ("io", io::add_signatures, io::add_docs),
47    ("fs", fs::add_signatures, fs::add_docs),
48    ("arith", arith::add_signatures, arith::add_docs),
49    ("stack", stack::add_signatures, stack::add_docs),
50    (
51        "concurrency",
52        concurrency::add_signatures,
53        concurrency::add_docs,
54    ),
55    ("callable", callable::add_signatures, callable::add_docs),
56    ("tcp", tcp::add_signatures, tcp::add_docs),
57    ("udp", udp::add_signatures, udp::add_docs),
58    ("dns", dns::add_signatures, dns::add_docs),
59    ("tls", tls::add_signatures, tls::add_docs),
60    ("http", http::add_signatures, http::add_docs),
61    ("os", os::add_signatures, os::add_docs),
62    ("text", text::add_signatures, text::add_docs),
63    ("adt", adt::add_signatures, adt::add_docs),
64    ("list", list::add_signatures, list::add_docs),
65    ("map", map::add_signatures, map::add_docs),
66    ("float", float::add_signatures, float::add_docs),
67    (
68        "diagnostics",
69        diagnostics::add_signatures,
70        diagnostics::add_docs,
71    ),
72];
73
74/// Get the stack-effect signature for a built-in word.
75pub fn builtin_signature(name: &str) -> Option<Effect> {
76    BUILTIN_SIGNATURES.get(name).cloned()
77}
78
79/// Build the full map of built-in word signatures.
80///
81/// Clones the cached map so callers that wanted ownership (e.g. tests,
82/// `TypeChecker::register_external_words`) keep working unchanged.
83pub fn builtin_signatures() -> HashMap<String, Effect> {
84    BUILTIN_SIGNATURES.clone()
85}
86
87static BUILTIN_SIGNATURES: LazyLock<HashMap<String, Effect>> = LazyLock::new(|| {
88    let mut sigs = HashMap::new();
89    for (_, add_sigs, _) in CATEGORIES {
90        add_sigs(&mut sigs);
91    }
92    sigs
93});
94
95/// Get documentation for a built-in word.
96pub fn builtin_doc(name: &str) -> Option<&'static str> {
97    BUILTIN_DOCS.get(name).copied()
98}
99
100/// Built-in words grouped by their category sub-module, in registration order.
101///
102/// Each entry is `(category_name, sorted_word_names)`. Useful for clients
103/// that want to render a categorised reference (e.g. a quick-help screen).
104pub fn builtin_categories() -> Vec<(&'static str, Vec<String>)> {
105    CATEGORIES
106        .iter()
107        .map(|(name, add_sigs, _)| {
108            let mut sigs = HashMap::new();
109            add_sigs(&mut sigs);
110            let mut words: Vec<String> = sigs.into_keys().collect();
111            words.sort();
112            (*name, words)
113        })
114        .collect()
115}
116
117/// Get all built-in word documentation (cached with LazyLock for performance).
118pub fn builtin_docs() -> &'static HashMap<&'static str, &'static str> {
119    &BUILTIN_DOCS
120}
121
122static BUILTIN_DOCS: LazyLock<HashMap<&'static str, &'static str>> = LazyLock::new(|| {
123    let mut docs = HashMap::new();
124    for (_, _, add_docs) in CATEGORIES {
125        add_docs(&mut docs);
126    }
127    docs
128});