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}