Skip to main content

bop/
stdlib.rs

1//! Bundled Bop standard library modules, resolved by name.
2//!
3//! Each `.bop` file under `src/modules/` is baked into the binary
4//! as an `&'static str` via `include_str!`. When a Bop script
5//! does `use std.math`, the engine asks its `BopHost` to
6//! resolve the module — embedders route that call to
7//! [`resolve`], which returns the bundled source text.
8//!
9//! Gated behind the `bop-std` feature (on by default). Disable
10//! with `default-features = false` when you want a truly minimal
11//! core with no bundled modules:
12//!
13//! ```toml
14//! bop-lang = { version = "0.3", default-features = false }
15//! ```
16//!
17//! Available modules:
18//!
19//! - `std.math` — numeric constants (`PI`, `E`, `TAU`) and
20//!   helpers that don't fit on a numeric receiver (`clamp`,
21//!   `factorial`, `gcd`, …)
22//! - `std.iter` — functional helpers on arrays (`map`, `filter`,
23//!   `reduce`, `sum`, `find`, …)
24//! - `std.string` — string helpers that didn't fit the
25//!   method-on-string pattern (`pad_left`, `pad_right`,
26//!   `chars`, …)
27//! - `std.test` — `assert`, `assert_eq`, `assert_near` plus a
28//!   tiny test-runner
29//! - `std.collections` — `Set`, `Queue`, `Stack` as struct
30//!   types with value-semantic methods (`s = s.push(v)` etc.)
31//! - `std.json` — `parse(text)` / `stringify(value)`. Pure
32//!   Bop implementation; adequate for scripting workloads.
33//!
34//! `Result` combinators (`is_ok`, `unwrap`, `map`, `and_then`,
35//! …) used to live in `std.result` but are now methods on the
36//! built-in `Result` type — always available without a `use`.
37//! See `methods::result_method`.
38
39const MATH: &str = include_str!("modules/math.bop");
40const ITER: &str = include_str!("modules/iter.bop");
41const STRING_MOD: &str = include_str!("modules/string.bop");
42const TEST_MOD: &str = include_str!("modules/test.bop");
43const COLLECTIONS: &str = include_str!("modules/collections.bop");
44const JSON_MOD: &str = include_str!("modules/json.bop");
45
46/// Map a `std.*` module name to its bundled Bop source.
47///
48/// Returns `None` for any path outside the stdlib — chain this
49/// with your own [`crate::BopHost::resolve_module`] so user
50/// modules still resolve:
51///
52/// ```ignore
53/// use bop::{BopError, BopHost};
54///
55/// impl BopHost for MyHost {
56///     fn resolve_module(&mut self, name: &str) -> Option<Result<String, BopError>> {
57///         if let Some(src) = bop::stdlib::resolve(name) {
58///             return Some(Ok(src.to_string()));
59///         }
60///         // fall back to your own resolver (filesystem,
61///         // embedded modules, etc.)
62///         self.my_own_resolver(name)
63///     }
64///     # fn call(&mut self, _: &str, _: &[bop::Value], _: u32)
65///     #     -> Option<Result<bop::Value, BopError>> { None }
66/// }
67/// # struct MyHost;
68/// # impl MyHost {
69/// #     fn my_own_resolver(&mut self, _: &str) -> Option<Result<String, BopError>> { None }
70/// # }
71/// ```
72pub fn resolve(name: &str) -> Option<&'static str> {
73    match name {
74        "std.math" => Some(MATH),
75        "std.iter" => Some(ITER),
76        "std.string" => Some(STRING_MOD),
77        "std.test" => Some(TEST_MOD),
78        "std.collections" => Some(COLLECTIONS),
79        "std.json" => Some(JSON_MOD),
80        _ => None,
81    }
82}
83
84/// Every module name this crate can resolve. Useful for docs,
85/// diagnostics, or a "did you mean…" suggestion in error paths.
86pub const MODULES: &[&str] = &[
87    "std.math",
88    "std.iter",
89    "std.string",
90    "std.test",
91    "std.collections",
92    "std.json",
93];
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    #[test]
100    fn resolve_returns_source_for_known_modules() {
101        for name in MODULES {
102            assert!(
103                resolve(name).is_some(),
104                "stdlib module {} should resolve",
105                name
106            );
107        }
108    }
109
110    #[test]
111    fn resolve_returns_none_for_unknown() {
112        assert!(resolve("std.nope").is_none());
113        assert!(resolve("user.code").is_none());
114        assert!(resolve("").is_none());
115    }
116}