1#![allow(clippy::mutable_key_type, clippy::cloned_ref_to_slice_refs)]
2mod arithmetic;
3mod async_ops;
4mod bitwise;
5mod bytevector;
6mod comparison;
7mod context;
8mod crypto;
9mod csv_ops;
10mod datetime;
11#[cfg(not(target_arch = "wasm32"))]
12mod http;
13#[cfg(not(target_arch = "wasm32"))]
14mod io;
15pub(crate) mod json;
16#[cfg(not(target_arch = "wasm32"))]
17mod kv;
18mod list;
19mod map;
20mod math;
21mod meta;
22mod otel;
23#[cfg(not(target_arch = "wasm32"))]
24mod pdf;
25mod pio;
26mod predicates;
27mod regex_ops;
28#[cfg(not(target_arch = "wasm32"))]
29mod serial;
30#[cfg(not(target_arch = "wasm32"))]
31mod server;
32#[cfg(not(target_arch = "wasm32"))]
33mod sqlite;
34mod stream;
35mod string;
36#[cfg(not(target_arch = "wasm32"))]
37mod system;
38#[cfg(not(target_arch = "wasm32"))]
39mod terminal;
40mod text;
41mod toml_ops;
42mod typed_array;
43
44#[cfg(not(target_arch = "wasm32"))]
45use sema_core::Caps;
46use sema_core::{Env, Sandbox, Value};
47
48pub fn register_stdlib(env: &Env, sandbox: &Sandbox) {
49 #[cfg(target_arch = "wasm32")]
50 let _ = sandbox;
51
52 arithmetic::register(env);
53 comparison::register(env);
54 context::register(env);
55 list::register(env);
56 string::register(env);
57 predicates::register(env);
58 map::register(env);
59 #[cfg(not(target_arch = "wasm32"))]
60 io::register(env, sandbox);
61 math::register(env);
62 #[cfg(not(target_arch = "wasm32"))]
63 system::register(env, sandbox);
64 json::register(env);
65 toml_ops::register(env);
66 meta::register(env);
67 otel::register(env);
68 regex_ops::register(env);
69 #[cfg(not(target_arch = "wasm32"))]
70 http::register(env, sandbox);
71 #[cfg(not(target_arch = "wasm32"))]
72 server::register(env, sandbox);
73 bitwise::register(env);
74 crypto::register(env);
75 datetime::register(env);
76 csv_ops::register(env);
77 bytevector::register(env);
78 #[cfg(not(target_arch = "wasm32"))]
79 terminal::register(env);
80 text::register(env);
81 stream::register(env);
82 pio::register(env);
83 typed_array::register(env);
84 async_ops::register(env);
85 #[cfg(not(target_arch = "wasm32"))]
86 stream::register_io(env, sandbox);
87 #[cfg(not(target_arch = "wasm32"))]
88 kv::register(env, sandbox);
89 #[cfg(not(target_arch = "wasm32"))]
90 pdf::register(env, sandbox);
91 #[cfg(not(target_arch = "wasm32"))]
92 sqlite::register(env, sandbox);
93 #[cfg(not(target_arch = "wasm32"))]
94 serial::register(env, sandbox);
95}
96
97#[cfg(not(target_arch = "wasm32"))]
98fn register_fn_gated(
99 env: &Env,
100 sandbox: &Sandbox,
101 cap: Caps,
102 name: &str,
103 f: impl Fn(&[Value]) -> Result<Value, sema_core::SemaError> + 'static,
104) {
105 if sandbox.is_unrestricted() {
106 register_fn(env, name, f);
107 } else {
108 let sandbox = sandbox.clone();
109 let fn_name = name.to_string();
110 register_fn(env, name, move |args| {
111 sandbox.check(cap, &fn_name)?;
112 f(args)
113 });
114 }
115}
116
117#[cfg(not(target_arch = "wasm32"))]
118fn register_fn_path_gated(
119 env: &Env,
120 sandbox: &Sandbox,
121 cap: Caps,
122 name: &str,
123 path_args: &[usize],
124 f: impl Fn(&[Value]) -> Result<Value, sema_core::SemaError> + 'static,
125) {
126 if sandbox.is_unrestricted() {
127 register_fn(env, name, f);
128 } else {
129 let sandbox = sandbox.clone();
130 let fn_name = name.to_string();
131 let path_indices: Vec<usize> = path_args.to_vec();
132 register_fn(env, name, move |args| {
133 sandbox.check(cap, &fn_name)?;
134 for &idx in &path_indices {
135 if let Some(val) = args.get(idx) {
136 if let Some(p) = val.as_str() {
137 sandbox.check_path(p, &fn_name)?;
138 }
139 }
140 }
141 f(args)
142 });
143 }
144}
145
146fn register_fn(
147 env: &Env,
148 name: &str,
149 f: impl Fn(&[Value]) -> Result<Value, sema_core::SemaError> + 'static,
150) {
151 env.set(
152 sema_core::intern(name),
153 Value::native_fn(sema_core::NativeFn::simple(name, f)),
154 );
155}