1use std::sync::{
2 Arc,
3 atomic::{AtomicU64, Ordering},
4};
5
6use crate::{
7 ContentId,
8 capability::{
9 CapabilityName, CapabilitySet, GrantSeat, macro_expansion_capability_for_phase,
10 read_construct_capability,
11 },
12 control::{ControlPolicy, ControlPolicyRef, NoopControlPolicy},
13 datum_store::BTreeDatumStore,
14 effect_ledger::EffectLedger,
15 error::{Diagnostic, Error, Result},
16 eval::{EvalPolicy, EvalPolicyRef, MacroExpanderRef, Phase},
17 expr::{Expr, SourceRegistry},
18 fact_store::{BTreeFactStore, FactStore},
19 factory::Factory,
20 handle_store::BTreeHandleStore,
21 id::{LibId, Symbol},
22 library::{LoadCx, Registry},
23 list::ListRegistry,
24 number_domain::PromotionSearchLimits,
25 object::Args,
26 table::TableRegistry,
27 value::Value,
28};
29
30use super::{Diagnostics, Env, load_ledger::LibLoadLedger};
31
32static NEXT_GRANT_ID: AtomicU64 = AtomicU64::new(1);
36
37fn unknown_symbol(symbol: &Symbol) -> Error {
38 Error::UnknownSymbol {
39 symbol: symbol.clone(),
40 }
41}
42
43fn class_protocol(value: &Value) -> Result<&dyn crate::Class> {
44 value.object().as_class().ok_or(Error::TypeMismatch {
45 expected: "class",
46 found: "non-class",
47 })
48}
49
50fn read_constructor_protocol(value: &Value) -> Result<&dyn crate::ReadConstructor> {
51 value
52 .object()
53 .as_read_constructor()
54 .ok_or(Error::TypeMismatch {
55 expected: "read-constructor",
56 found: "non-read-constructor",
57 })
58}
59
60pub type Capabilities = CapabilitySet;
62
63pub struct Cx {
72 grant_id: u64,
77 env: Env,
78 diagnostics: Diagnostics,
79 capabilities: Capabilities,
80 eval_policy: EvalPolicyRef,
81 macro_expander: Option<MacroExpanderRef>,
82 factory: Arc<dyn Factory>,
83 pub(crate) registry: Registry,
84 list_registry: ListRegistry,
85 table_registry: TableRegistry,
86 promotion_search_limits: PromotionSearchLimits,
87 sources: SourceRegistry,
88 datum_store: BTreeDatumStore,
89 handles: BTreeHandleStore,
90 facts: BTreeFactStore,
91 lib_load_ledger: LibLoadLedger,
92 effect_ledger: EffectLedger,
93 control_policy: ControlPolicyRef,
94}
95
96impl Cx {
97 pub fn new(eval_policy: EvalPolicyRef, factory: Arc<dyn Factory>) -> Self {
111 let mut datum_store = BTreeDatumStore::default();
112 let mut facts = BTreeFactStore::default();
113 facts.insert_boot_claims(&mut datum_store);
114
115 Self {
116 grant_id: NEXT_GRANT_ID.fetch_add(1, Ordering::Relaxed),
117 env: Env::default(),
118 diagnostics: Diagnostics::default(),
119 capabilities: Capabilities::default(),
120 eval_policy,
121 macro_expander: None,
122 factory,
123 registry: Registry::default(),
124 list_registry: ListRegistry::default(),
125 table_registry: TableRegistry::default(),
126 promotion_search_limits: PromotionSearchLimits::default(),
127 sources: SourceRegistry::default(),
128 datum_store,
129 handles: BTreeHandleStore::default(),
130 facts,
131 lib_load_ledger: LibLoadLedger::default(),
132 effect_ledger: EffectLedger::default(),
133 control_policy: Arc::new(NoopControlPolicy),
134 }
135 }
136
137 pub fn env(&self) -> &Env {
139 &self.env
140 }
141
142 pub fn env_mut(&mut self) -> &mut Env {
144 &mut self.env
145 }
146
147 pub fn with_env<T>(&mut self, env: Env, f: impl FnOnce(&mut Self) -> Result<T>) -> Result<T> {
149 let saved = std::mem::replace(&mut self.env, env);
150 let result = f(self);
151 self.env = saved;
152 result
153 }
154
155 pub fn factory(&self) -> &dyn Factory {
157 self.factory.as_ref()
158 }
159
160 pub fn factory_ref(&self) -> Arc<dyn Factory> {
162 self.factory.clone()
163 }
164
165 pub fn with_factory<T>(
167 &mut self,
168 factory: Arc<dyn Factory>,
169 f: impl FnOnce(&mut Self) -> Result<T>,
170 ) -> Result<T> {
171 let saved = std::mem::replace(&mut self.factory, factory);
172 let result = f(self);
173 self.factory = saved;
174 result
175 }
176
177 pub fn registry(&self) -> &Registry {
179 &self.registry
180 }
181
182 pub fn registry_mut(&mut self) -> &mut Registry {
184 &mut self.registry
185 }
186
187 pub fn list_registry(&self) -> &ListRegistry {
189 &self.list_registry
190 }
191
192 pub fn list_registry_mut(&mut self) -> &mut ListRegistry {
194 &mut self.list_registry
195 }
196
197 pub fn table_registry(&self) -> &TableRegistry {
199 &self.table_registry
200 }
201
202 pub fn table_registry_mut(&mut self) -> &mut TableRegistry {
204 &mut self.table_registry
205 }
206
207 pub fn with_registry<T>(
209 &mut self,
210 registry: Registry,
211 f: impl FnOnce(&mut Self) -> Result<T>,
212 ) -> Result<T> {
213 let saved = std::mem::replace(&mut self.registry, registry);
214 let result = f(self);
215 self.registry = saved;
216 result
217 }
218
219 pub fn new_list(&mut self, items: Vec<Value>) -> Result<Value> {
221 let registry = std::mem::take(&mut self.list_registry);
222 let result = registry.new_list(self, items);
223 self.list_registry = registry;
224 result
225 }
226
227 pub fn new_cons(&mut self, car: Value, cdr: Value) -> Result<Value> {
229 let registry = std::mem::take(&mut self.list_registry);
230 let result = registry.new_cons(self, car, cdr);
231 self.list_registry = registry;
232 result
233 }
234
235 pub fn new_table(&mut self, entries: Vec<(Symbol, Value)>) -> Result<Value> {
237 let registry = std::mem::take(&mut self.table_registry);
238 let result = registry.new_table(self, entries);
239 self.table_registry = registry;
240 result
241 }
242
243 pub fn sources(&self) -> &SourceRegistry {
245 &self.sources
246 }
247
248 pub fn sources_mut(&mut self) -> &mut SourceRegistry {
250 &mut self.sources
251 }
252
253 pub fn datum_store(&self) -> &BTreeDatumStore {
255 &self.datum_store
256 }
257
258 pub fn datum_store_mut(&mut self) -> &mut BTreeDatumStore {
260 &mut self.datum_store
261 }
262
263 pub fn handles(&self) -> &BTreeHandleStore {
265 &self.handles
266 }
267
268 pub fn handles_mut(&mut self) -> &mut BTreeHandleStore {
270 &mut self.handles
271 }
272
273 pub fn facts(&self) -> &BTreeFactStore {
275 &self.facts
276 }
277
278 pub fn facts_mut(&mut self) -> &mut BTreeFactStore {
280 &mut self.facts
281 }
282
283 pub fn effect_ledger(&self) -> &EffectLedger {
285 &self.effect_ledger
286 }
287
288 pub fn effect_ledger_mut(&mut self) -> &mut EffectLedger {
290 &mut self.effect_ledger
291 }
292
293 pub fn control_policy(&self) -> &dyn ControlPolicy {
295 self.control_policy.as_ref()
296 }
297
298 pub fn control_policy_ref(&self) -> ControlPolicyRef {
300 self.control_policy.clone()
301 }
302
303 pub fn control_policy_name(&self) -> &'static str {
305 self.control_policy.name()
306 }
307
308 pub fn set_control_policy(&mut self, control_policy: ControlPolicyRef) {
310 self.control_policy = control_policy;
311 }
312
313 pub(crate) fn with_effect_ledger<T>(
314 &mut self,
315 f: impl FnOnce(&mut Self, &mut EffectLedger) -> Result<T>,
316 ) -> Result<T> {
317 let mut ledger = std::mem::take(&mut self.effect_ledger);
318 let result = f(self, &mut ledger);
319 self.effect_ledger = ledger;
320 result
321 }
322
323 pub fn insert_fact(&mut self, claim: crate::Claim) -> Result<crate::Ref> {
325 self.facts
326 .insert_authorized(&self.capabilities, &mut self.datum_store, claim)
327 }
328
329 pub fn insert_fact_for_lib(
335 &mut self,
336 lib_id: LibId,
337 claim: crate::Claim,
338 ) -> Result<crate::Ref> {
339 let (reference, inserted) = self.insert_recorded_fact(claim)?;
340 if let Some(inserted) = inserted {
341 self.record_load_claims(lib_id, vec![inserted]);
342 }
343 Ok(reference)
344 }
345
346 pub(crate) fn insert_recorded_fact(
347 &mut self,
348 claim: crate::Claim,
349 ) -> Result<(crate::Ref, Option<ContentId>)> {
350 let id = claim.content_id(&mut self.datum_store)?;
351 let existed = self.facts.get(&id).is_some();
352 let inserted = self.insert_fact(claim)?;
353 let crate::Ref::Content(inserted_id) = inserted else {
354 return Err(Error::Lib(
355 "fact insertion returned a non-content reference".to_owned(),
356 ));
357 };
358 debug_assert_eq!(inserted_id, id);
359 Ok((
360 crate::Ref::Content(inserted_id.clone()),
361 (!existed).then_some(inserted_id),
362 ))
363 }
364
365 pub fn query_facts(&self, pattern: crate::ClaimPattern) -> Result<Vec<crate::Claim>> {
367 self.facts.query_authorized(self, pattern)
368 }
369
370 pub(crate) fn record_load_claims(&mut self, lib_id: LibId, claim_ids: Vec<ContentId>) {
371 self.lib_load_ledger.record_claims(lib_id, claim_ids);
372 }
373
374 pub(crate) fn remove_load_claims(&mut self, lib_ids: &[LibId]) {
375 self.lib_load_ledger.remove_claims(lib_ids, &mut self.facts);
376 }
377
378 pub fn promotion_search_limits(&self) -> PromotionSearchLimits {
380 self.promotion_search_limits
381 }
382
383 pub fn set_promotion_search_limits(&mut self, limits: PromotionSearchLimits) {
385 self.promotion_search_limits = limits;
386 }
387
388 pub(crate) fn load_cx(&self) -> LoadCx {
389 LoadCx::new(
390 self.capabilities.clone(),
391 self.factory.clone(),
392 self.registry.clone(),
393 )
394 }
395
396 pub fn eval_policy(&self) -> &dyn EvalPolicy {
398 self.eval_policy.as_ref()
399 }
400
401 pub fn eval_policy_ref(&self) -> EvalPolicyRef {
403 self.eval_policy.clone()
404 }
405
406 pub fn eval_policy_name(&self) -> &'static str {
408 self.eval_policy.name()
409 }
410
411 pub fn set_eval_policy(&mut self, eval_policy: EvalPolicyRef) {
413 self.eval_policy = eval_policy;
414 }
415
416 pub fn set_macro_expander(&mut self, macro_expander: MacroExpanderRef) {
418 self.macro_expander = Some(macro_expander);
419 }
420
421 pub fn clear_macro_expander(&mut self) {
423 self.macro_expander = None;
424 }
425
426 pub fn macro_expander_ref(&self) -> Option<MacroExpanderRef> {
428 self.macro_expander.clone()
429 }
430
431 pub fn expand_macros(&mut self, phase: Phase, expr: Expr) -> Result<Expr> {
433 let Some(expander) = self.macro_expander.clone() else {
434 return Ok(expr);
435 };
436 let eval_policy = self.eval_policy_ref();
437 if !eval_policy.allow_macro_expansion(phase) {
438 return Err(Error::Eval(format!(
439 "macro expansion denied by eval policy {} for {phase:?}",
440 eval_policy.name()
441 )));
442 }
443 self.require(¯o_expansion_capability_for_phase(phase))?;
444 expander.expand_expr(self, phase, expr)
445 }
446
447 pub fn diagnostics(&self) -> &Diagnostics {
449 &self.diagnostics
450 }
451
452 pub fn take_diagnostics(&mut self) -> Vec<Diagnostic> {
454 self.diagnostics.take()
455 }
456
457 pub fn push_diagnostic(&mut self, diagnostic: Diagnostic) {
459 self.diagnostics.push_diagnostic(diagnostic);
460 }
461
462 pub fn push_info(&mut self, message: impl Into<String>) {
464 self.diagnostics.push_info(message);
465 }
466
467 pub fn new_seated(eval_policy: EvalPolicyRef, factory: Arc<dyn Factory>) -> (Self, GrantSeat) {
474 let cx = Self::new(eval_policy, factory);
475 let seat = GrantSeat::for_cx(cx.grant_id);
476 (cx, seat)
477 }
478
479 pub(crate) fn grant_id(&self) -> u64 {
481 self.grant_id
482 }
483
484 pub(crate) fn grant_from_host(&mut self, capability: CapabilityName) {
491 self.capabilities.insert(capability);
492 }
493
494 #[cfg(feature = "test-support")]
498 pub fn grant(&mut self, capability: CapabilityName) {
499 self.grant_from_host(capability);
500 }
501
502 #[cfg(feature = "test-support")]
505 pub fn grant_named(&mut self, capability: &'static str) {
506 self.grant_from_host(CapabilityName::new(capability));
507 }
508
509 pub fn capabilities(&self) -> &Capabilities {
511 &self.capabilities
512 }
513
514 pub fn with_capabilities<T>(
516 &mut self,
517 capabilities: Capabilities,
518 f: impl FnOnce(&mut Self) -> Result<T>,
519 ) -> Result<T> {
520 let saved = std::mem::replace(&mut self.capabilities, capabilities);
521 let result = f(self);
522 self.capabilities = saved;
523 result
524 }
525
526 pub fn resolve_class(&self, symbol: &Symbol) -> Result<Value> {
528 self.resolve_registered_value(
529 |registry| registry.class_by_symbol(symbol),
530 Error::UnknownClass {
531 class: symbol.clone(),
532 },
533 )
534 }
535
536 pub fn resolve_function(&self, symbol: &Symbol) -> Result<Value> {
538 self.resolve_registered_value(
539 |registry| registry.function_by_symbol(symbol),
540 Error::UnknownFunction {
541 function: symbol.clone(),
542 },
543 )
544 }
545
546 pub fn resolve_macro(&self, symbol: &Symbol) -> Result<Value> {
548 self.resolve_registered_value(
549 |registry| registry.macro_by_symbol(symbol),
550 unknown_symbol(symbol),
551 )
552 }
553
554 pub fn resolve_shape(&self, symbol: &Symbol) -> Result<Value> {
556 self.resolve_registered_value(
557 |registry| registry.shape_by_symbol(symbol),
558 unknown_symbol(symbol),
559 )
560 }
561
562 pub fn resolve_codec(&self, symbol: &Symbol) -> Result<Value> {
564 self.resolve_registered_value(
565 |registry| registry.codec_by_symbol(symbol),
566 unknown_symbol(symbol),
567 )
568 }
569
570 pub fn resolve_number_domain(&self, symbol: &Symbol) -> Result<Value> {
572 self.resolve_registered_value(
573 |registry| registry.number_domain_by_symbol(symbol),
574 unknown_symbol(symbol),
575 )
576 }
577
578 pub fn resolve_value(&self, symbol: &Symbol) -> Result<Value> {
580 self.resolve_registered_value(
581 |registry| registry.value_by_symbol(symbol),
582 unknown_symbol(symbol),
583 )
584 }
585
586 fn resolve_registered_value(
587 &self,
588 lookup: impl FnOnce(&Registry) -> Option<&Value>,
589 not_found: Error,
590 ) -> Result<Value> {
591 lookup(self.registry()).cloned().ok_or(not_found)
592 }
593
594 pub fn call_value(&mut self, value: Value, args: Args) -> Result<Value> {
596 let Some(callable) = value.object().as_callable() else {
597 return Err(Error::TypeMismatch {
598 expected: "callable",
599 found: "non-callable",
600 });
601 };
602 callable.call(self, args)
603 }
604
605 pub fn call_exprs(&mut self, value: Value, args: Vec<crate::expr::Expr>) -> Result<Value> {
607 let Some(callable) = value.object().as_callable() else {
608 return Err(Error::TypeMismatch {
609 expected: "callable",
610 found: "non-callable",
611 });
612 };
613 callable.call_exprs(self, crate::object::RawArgs::new(args))
614 }
615
616 pub fn call_function(&mut self, symbol: &Symbol, args: Args) -> Result<Value> {
618 let function = self.resolve_function(symbol)?;
619 self.call_value(function, args)
620 }
621
622 pub fn call_class(&mut self, symbol: &Symbol, args: Args) -> Result<Value> {
624 let class = self.resolve_class(symbol)?;
625 self.call_value(class, args)
626 }
627
628 pub fn read_construct(&mut self, class: &Symbol, args: Vec<Value>) -> Result<Value> {
632 self.require(&read_construct_capability())?;
633 let class_value = self.resolve_class(class)?;
634 let constructor = class_protocol(&class_value)?
635 .read_constructor(self)?
636 .ok_or_else(|| Error::Eval(format!("class {class} has no read constructor")))?;
637 read_constructor_protocol(&constructor)?.construct_read(self, args)
638 }
639
640 pub fn force(&mut self, value: Value, demand: crate::eval::Demand) -> Result<Value> {
642 let eval_policy = self.eval_policy.clone();
643 eval_policy.force(self, value, demand)
644 }
645
646 pub fn eval_expr(&mut self, expr: crate::expr::Expr) -> Result<Value> {
648 let eval_policy = self.eval_policy.clone();
649 eval_policy.eval_expr(self, expr)
650 }
651
652 pub fn symbol_is_bound(&mut self, name: &Symbol) -> bool {
654 self.env().get(name).is_some()
655 || self.resolve_function(name).is_ok()
656 || self.resolve_class(name).is_ok()
657 || self.resolve_shape(name).is_ok()
658 || self.resolve_value(name).is_ok()
659 }
660
661 pub fn resolve_unbound_symbol(&mut self, symbol: Symbol) -> Result<Value> {
663 let eval_policy = self.eval_policy_ref();
664 eval_policy.resolve_unbound_symbol(self, symbol)
665 }
666
667 pub fn resolve_unbound_call(
669 &mut self,
670 operator: Symbol,
671 args: Vec<crate::expr::Expr>,
672 ) -> Result<Value> {
673 let eval_policy = self.eval_policy_ref();
674 eval_policy.resolve_unbound_call(self, operator, args)
675 }
676
677 pub fn require(&self, capability: &CapabilityName) -> Result<()> {
679 if self.capabilities.contains(capability) {
680 Ok(())
681 } else {
682 Err(Error::CapabilityDenied {
683 capability: capability.clone(),
684 })
685 }
686 }
687
688 pub fn require_all(&self, capabilities: &[CapabilityName]) -> Result<()> {
690 for capability in capabilities {
691 self.require(capability)?;
692 }
693 Ok(())
694 }
695}