1#[macro_use]
2extern crate netidx_core;
3#[macro_use]
4extern crate combine;
5#[macro_use]
6extern crate serde_derive;
7
8pub mod env;
9pub mod expr;
10pub mod node;
11pub mod rt;
12pub mod stdfn;
13pub mod typ;
14
15use crate::{
16 env::Env,
17 expr::{ExprId, ExprKind, ModPath},
18 typ::{FnType, Type},
19};
20use anyhow::{bail, Result};
21use arcstr::ArcStr;
22use expr::Expr;
23use fxhash::FxHashMap;
24use netidx::{
25 path::Path,
26 publisher::{Id, Val, WriteRequest},
27 subscriber::{self, Dval, SubId, UpdatesFlags, Value},
28};
29use netidx_protocols::rpc::server::{ArgSpec, RpcCall};
30use node::compiler;
31use parking_lot::RwLock;
32use std::{
33 collections::{hash_map::Entry, HashMap},
34 fmt::Debug,
35 sync::{self, LazyLock},
36 time::Duration,
37};
38use triomphe::Arc;
39
40#[cfg(test)]
41#[macro_use]
42mod tests;
43
44atomic_id!(BindId);
45atomic_id!(LambdaId);
46
47impl BindId {
48 pub(crate) fn from_u64(v: u64) -> Self {
49 BindId(v)
50 }
51}
52
53#[macro_export]
54macro_rules! errf {
55 ($pat:expr, $($arg:expr),*) => {
56 Some(Value::Error(ArcStr::from(format_compact!($pat, $($arg),*).as_str())))
57 };
58 ($pat:expr) => { Some(Value::Error(ArcStr::from(format_compact!($pat).as_str()))) };
59}
60
61#[macro_export]
62macro_rules! err {
63 ($pat:literal) => {
64 Some(Value::Error(literal!($pat)))
65 };
66}
67
68pub trait UserEvent: Clone + Debug + 'static {
69 fn clear(&mut self);
70}
71
72#[derive(Debug, Clone)]
73pub struct NoUserEvent;
74
75impl UserEvent for NoUserEvent {
76 fn clear(&mut self) {}
77}
78
79#[derive(Debug)]
85pub struct Event<E: UserEvent> {
86 pub init: bool,
87 pub variables: FxHashMap<BindId, Value>,
88 pub netidx: FxHashMap<SubId, subscriber::Event>,
89 pub writes: FxHashMap<Id, WriteRequest>,
90 pub rpc_calls: FxHashMap<BindId, RpcCall>,
91 pub user: E,
92}
93
94impl<E: UserEvent> Event<E> {
95 pub fn new(user: E) -> Self {
96 Event {
97 init: false,
98 variables: HashMap::default(),
99 netidx: HashMap::default(),
100 writes: HashMap::default(),
101 rpc_calls: HashMap::default(),
102 user,
103 }
104 }
105
106 pub fn clear(&mut self) {
107 let Self { init, variables, netidx, rpc_calls, writes, user } = self;
108 *init = false;
109 variables.clear();
110 netidx.clear();
111 rpc_calls.clear();
112 writes.clear();
113 user.clear();
114 }
115}
116
117pub type Node<C, E> = Box<dyn Update<C, E>>;
118
119pub type BuiltInInitFn<C, E> = sync::Arc<
120 dyn for<'a, 'b, 'c> Fn(
121 &'a mut ExecCtx<C, E>,
122 &'a FnType,
123 &'b ModPath,
124 &'c [Node<C, E>],
125 ExprId,
126 ) -> Result<Box<dyn Apply<C, E>>>
127 + Send
128 + Sync
129 + 'static,
130>;
131
132pub type InitFn<C, E> = sync::Arc<
133 dyn for<'a, 'b> Fn(
134 &'a mut ExecCtx<C, E>,
135 &'b [Node<C, E>],
136 ExprId,
137 ) -> Result<Box<dyn Apply<C, E>>>
138 + Send
139 + Sync
140 + 'static,
141>;
142
143pub trait Apply<C: Ctx, E: UserEvent>: Debug + Send + Sync + 'static {
148 fn update(
149 &mut self,
150 ctx: &mut ExecCtx<C, E>,
151 from: &mut [Node<C, E>],
152 event: &mut Event<E>,
153 ) -> Option<Value>;
154
155 fn delete(&mut self, _ctx: &mut ExecCtx<C, E>) {
158 ()
159 }
160
161 fn typecheck(
164 &mut self,
165 _ctx: &mut ExecCtx<C, E>,
166 _from: &mut [Node<C, E>],
167 ) -> Result<()> {
168 Ok(())
169 }
170
171 fn typ(&self) -> Arc<FnType> {
174 const EMPTY: LazyLock<Arc<FnType>> = LazyLock::new(|| {
175 Arc::new(FnType {
176 args: Arc::from_iter([]),
177 constraints: Arc::new(RwLock::new(vec![])),
178 rtype: Type::Bottom,
179 vargs: None,
180 })
181 });
182 Arc::clone(&*EMPTY)
183 }
184
185 fn refs<'a>(&'a self, _f: &'a mut (dyn FnMut(BindId) + 'a)) {
190 ()
191 }
192}
193
194pub trait Update<C: Ctx, E: UserEvent>: Debug + Send + Sync + 'static {
198 fn update(&mut self, ctx: &mut ExecCtx<C, E>, event: &mut Event<E>) -> Option<Value>;
201
202 fn delete(&mut self, ctx: &mut ExecCtx<C, E>);
204
205 fn typecheck(&mut self, ctx: &mut ExecCtx<C, E>) -> Result<()>;
207
208 fn typ(&self) -> &Type;
210
211 fn refs<'a>(&'a self, f: &'a mut (dyn FnMut(BindId) + 'a));
213
214 fn spec(&self) -> &Expr;
216}
217
218pub trait BuiltIn<C: Ctx, E: UserEvent> {
219 const NAME: &str;
220 const TYP: LazyLock<FnType>;
221
222 fn init(ctx: &mut ExecCtx<C, E>) -> BuiltInInitFn<C, E>;
223}
224
225pub trait Ctx: Debug + 'static {
226 fn clear(&mut self);
227
228 fn subscribe(&mut self, flags: UpdatesFlags, path: Path, ref_by: ExprId) -> Dval;
232
233 fn unsubscribe(&mut self, path: Path, dv: Dval, ref_by: ExprId);
235
236 fn list(&mut self, id: BindId, path: Path);
241
242 fn list_table(&mut self, id: BindId, path: Path);
245
246 fn stop_list(&mut self, id: BindId);
249
250 fn publish(&mut self, path: Path, value: Value, ref_by: ExprId) -> Result<Val>;
254
255 fn update(&mut self, id: &Val, value: Value);
257
258 fn unpublish(&mut self, id: Val, ref_by: ExprId);
260
261 fn ref_var(&mut self, id: BindId, ref_by: ExprId);
271 fn unref_var(&mut self, id: BindId, ref_by: ExprId);
272
273 fn set_var(&mut self, id: BindId, value: Value);
285
286 fn call_rpc(&mut self, name: Path, args: Vec<(ArcStr, Value)>, id: BindId);
292
293 fn publish_rpc(
302 &mut self,
303 name: Path,
304 doc: Value,
305 spec: Vec<ArgSpec>,
306 id: BindId,
307 ) -> Result<()>;
308
309 fn unpublish_rpc(&mut self, name: Path);
311
312 fn set_timer(&mut self, id: BindId, timeout: Duration);
316}
317
318pub struct ExecCtx<C: Ctx, E: UserEvent> {
319 builtins: FxHashMap<&'static str, (FnType, BuiltInInitFn<C, E>)>,
320 std: Vec<Node<C, E>>,
321 pub env: Env<C, E>,
322 pub cached: FxHashMap<BindId, Value>,
323 pub user: C,
324}
325
326impl<C: Ctx, E: UserEvent> ExecCtx<C, E> {
327 pub fn clear(&mut self) {
328 self.env.clear();
329 self.user.clear();
330 }
331
332 pub fn new_no_std(user: C) -> Self {
334 let mut t = ExecCtx {
335 env: Env::new(),
336 builtins: FxHashMap::default(),
337 std: vec![],
338 cached: HashMap::default(),
339 user,
340 };
341 let core = stdfn::core::register(&mut t);
342 let root = ModPath(Path::root());
343 let node = compile(&mut t, &root, core).expect("error compiling core");
344 t.std.push(node);
345 let node = compile(
346 &mut t,
347 &root,
348 ExprKind::Use { name: ModPath::from(["core"]) }.to_expr(Default::default()),
349 )
350 .expect("error compiling use core");
351 t.std.push(node);
352 t
353 }
354
355 pub fn new(user: C) -> Self {
357 let mut t = Self::new_no_std(user);
358 let root = ModPath(Path::root());
359 let str = stdfn::str::register(&mut t);
360 let node = compile(&mut t, &root, str).expect("failed to compile the str module");
361 t.std.push(node);
362 let re = stdfn::re::register(&mut t);
363 let node = compile(&mut t, &root, re).expect("failed to compile the re module");
364 t.std.push(node);
365 let time = stdfn::time::register(&mut t);
366 let node =
367 compile(&mut t, &root, time).expect("failed to compile the time module");
368 t.std.push(node);
369 let rand = stdfn::rand::register(&mut t);
370 let node = compile(&mut t, &root, rand).expect("failed to compile rand module");
371 t.std.push(node);
372 let net = stdfn::net::register(&mut t);
373 let node = compile(&mut t, &root, net).expect("failed to compile the net module");
374 t.std.push(node);
375 t
376 }
377
378 pub fn register_builtin<T: BuiltIn<C, E>>(&mut self) -> Result<()> {
379 let f = T::init(self);
380 match self.builtins.entry(T::NAME) {
381 Entry::Vacant(e) => {
382 e.insert((T::TYP.clone(), f));
383 }
384 Entry::Occupied(_) => bail!("builtin {} is already registered", T::NAME),
385 }
386 Ok(())
387 }
388
389 pub fn set_var(&mut self, id: BindId, v: Value) {
393 self.cached.insert(id, v.clone());
394 self.user.set_var(id, v)
395 }
396}
397
398pub fn compile<C: Ctx, E: UserEvent>(
401 ctx: &mut ExecCtx<C, E>,
402 scope: &ModPath,
403 spec: Expr,
404) -> Result<Node<C, E>> {
405 let top_id = spec.id;
406 let env = ctx.env.clone();
407 let mut node = match compiler::compile(ctx, spec, scope, top_id) {
408 Ok(n) => n,
409 Err(e) => {
410 ctx.env = env;
411 return Err(e);
412 }
413 };
414 if let Err(e) = node.typecheck(ctx) {
415 ctx.env = env;
416 return Err(e);
417 }
418 Ok(node)
419}