Skip to main content

sim_kernel/env/
core.rs

1use std::{collections::BTreeMap, sync::Arc};
2
3use crate::{
4    ContentId,
5    capability::{CapabilityName, CapabilitySet, read_construct_capability},
6    control::{ControlPolicy, ControlPolicyRef, NoopControlPolicy},
7    datum_store::BTreeDatumStore,
8    effect_ledger::EffectLedger,
9    error::{Diagnostic, Error, Result},
10    eval::{EvalPolicy, EvalPolicyRef, MacroExpanderRef, Phase},
11    expr::{Expr, SourceRegistry},
12    fact_store::{BTreeFactStore, FactStore},
13    factory::Factory,
14    handle_store::BTreeHandleStore,
15    id::{LibId, Symbol},
16    library::{LoadCx, Registry},
17    list::ListRegistry,
18    number_domain::PromotionSearchLimits,
19    object::Args,
20    table::TableRegistry,
21    value::Value,
22};
23
24use super::{Diagnostics, Env};
25
26/// The capability state of a [`Cx`]; an alias for [`CapabilitySet`].
27pub type Capabilities = CapabilitySet;
28
29/// The evaluation context threaded through every checked call.
30///
31/// `Cx` bundles the registry handle, factory, capability set, eval and control
32/// policies, the data substrate (datum/fact/handle stores and ledgers), and the
33/// diagnostic sink. The kernel defines this context; libraries supply the
34/// behavior reached through it (registered classes, functions, number domains,
35/// list/table backends, and so on). See the README sections "Library system"
36/// and "Capabilities and trust".
37pub struct Cx {
38    env: Env,
39    diagnostics: Diagnostics,
40    capabilities: Capabilities,
41    eval_policy: EvalPolicyRef,
42    macro_expander: Option<MacroExpanderRef>,
43    factory: Arc<dyn Factory>,
44    pub(crate) registry: Registry,
45    list_registry: ListRegistry,
46    table_registry: TableRegistry,
47    promotion_search_limits: PromotionSearchLimits,
48    sources: SourceRegistry,
49    datum_store: BTreeDatumStore,
50    handles: BTreeHandleStore,
51    facts: BTreeFactStore,
52    load_claims: BTreeMap<LibId, Vec<ContentId>>,
53    effect_ledger: EffectLedger,
54    control_policy: ControlPolicyRef,
55}
56
57impl Cx {
58    /// Builds a fresh context with the given eval policy and factory.
59    ///
60    /// The registry, capability set, and stores start empty (boot claims aside);
61    /// libraries register behavior into the returned context.
62    ///
63    /// # Examples
64    ///
65    /// ```
66    /// # use std::sync::Arc;
67    /// # use sim_kernel::{Cx, DefaultFactory, NoopEvalPolicy};
68    /// let cx = Cx::new(Arc::new(NoopEvalPolicy), Arc::new(DefaultFactory));
69    /// assert!(cx.capabilities().iter().next().is_none());
70    /// ```
71    pub fn new(eval_policy: EvalPolicyRef, factory: Arc<dyn Factory>) -> Self {
72        let mut datum_store = BTreeDatumStore::default();
73        let mut facts = BTreeFactStore::default();
74        facts.insert_boot_claims(&mut datum_store);
75
76        Self {
77            env: Env::default(),
78            diagnostics: Diagnostics::default(),
79            capabilities: Capabilities::default(),
80            eval_policy,
81            macro_expander: None,
82            factory,
83            registry: Registry::default(),
84            list_registry: ListRegistry::default(),
85            table_registry: TableRegistry::default(),
86            promotion_search_limits: PromotionSearchLimits::default(),
87            sources: SourceRegistry::default(),
88            datum_store,
89            handles: BTreeHandleStore::default(),
90            facts,
91            load_claims: BTreeMap::new(),
92            effect_ledger: EffectLedger::default(),
93            control_policy: Arc::new(NoopControlPolicy),
94        }
95    }
96
97    /// Returns the active lexical environment.
98    pub fn env(&self) -> &Env {
99        &self.env
100    }
101
102    /// Returns the active lexical environment mutably.
103    pub fn env_mut(&mut self) -> &mut Env {
104        &mut self.env
105    }
106
107    /// Runs `f` with `env` installed as the active environment, then restores it.
108    pub fn with_env<T>(&mut self, env: Env, f: impl FnOnce(&mut Self) -> Result<T>) -> Result<T> {
109        let saved = std::mem::replace(&mut self.env, env);
110        let result = f(self);
111        self.env = saved;
112        result
113    }
114
115    /// Returns the active object [`Factory`].
116    pub fn factory(&self) -> &dyn Factory {
117        self.factory.as_ref()
118    }
119
120    /// Returns a shared handle to the active object factory.
121    pub fn factory_ref(&self) -> Arc<dyn Factory> {
122        self.factory.clone()
123    }
124
125    /// Runs `f` with `factory` installed as the active factory, then restores it.
126    pub fn with_factory<T>(
127        &mut self,
128        factory: Arc<dyn Factory>,
129        f: impl FnOnce(&mut Self) -> Result<T>,
130    ) -> Result<T> {
131        let saved = std::mem::replace(&mut self.factory, factory);
132        let result = f(self);
133        self.factory = saved;
134        result
135    }
136
137    /// Returns the behavior [`Registry`].
138    pub fn registry(&self) -> &Registry {
139        &self.registry
140    }
141
142    /// Returns the behavior registry mutably, for registering exports.
143    pub fn registry_mut(&mut self) -> &mut Registry {
144        &mut self.registry
145    }
146
147    /// Returns the registered list backend.
148    pub fn list_registry(&self) -> &ListRegistry {
149        &self.list_registry
150    }
151
152    /// Returns the list backend mutably.
153    pub fn list_registry_mut(&mut self) -> &mut ListRegistry {
154        &mut self.list_registry
155    }
156
157    /// Returns the registered table backend.
158    pub fn table_registry(&self) -> &TableRegistry {
159        &self.table_registry
160    }
161
162    /// Returns the table backend mutably.
163    pub fn table_registry_mut(&mut self) -> &mut TableRegistry {
164        &mut self.table_registry
165    }
166
167    /// Runs `f` with `registry` installed as the active registry, then restores it.
168    pub fn with_registry<T>(
169        &mut self,
170        registry: Registry,
171        f: impl FnOnce(&mut Self) -> Result<T>,
172    ) -> Result<T> {
173        let saved = std::mem::replace(&mut self.registry, registry);
174        let result = f(self);
175        self.registry = saved;
176        result
177    }
178
179    /// Builds a list value through the registered list backend.
180    pub fn new_list(&mut self, items: Vec<Value>) -> Result<Value> {
181        let registry = std::mem::take(&mut self.list_registry);
182        let result = registry.new_list(self, items);
183        self.list_registry = registry;
184        result
185    }
186
187    /// Builds a cons cell through the registered list backend.
188    pub fn new_cons(&mut self, car: Value, cdr: Value) -> Result<Value> {
189        let registry = std::mem::take(&mut self.list_registry);
190        let result = registry.new_cons(self, car, cdr);
191        self.list_registry = registry;
192        result
193    }
194
195    /// Builds a table value through the registered table backend.
196    pub fn new_table(&mut self, entries: Vec<(Symbol, Value)>) -> Result<Value> {
197        let registry = std::mem::take(&mut self.table_registry);
198        let result = registry.new_table(self, entries);
199        self.table_registry = registry;
200        result
201    }
202
203    /// Returns the source registry.
204    pub fn sources(&self) -> &SourceRegistry {
205        &self.sources
206    }
207
208    /// Returns the source registry mutably.
209    pub fn sources_mut(&mut self) -> &mut SourceRegistry {
210        &mut self.sources
211    }
212
213    /// Returns the datum store.
214    pub fn datum_store(&self) -> &BTreeDatumStore {
215        &self.datum_store
216    }
217
218    /// Returns the datum store mutably.
219    pub fn datum_store_mut(&mut self) -> &mut BTreeDatumStore {
220        &mut self.datum_store
221    }
222
223    /// Returns the handle store.
224    pub fn handles(&self) -> &BTreeHandleStore {
225        &self.handles
226    }
227
228    /// Returns the handle store mutably.
229    pub fn handles_mut(&mut self) -> &mut BTreeHandleStore {
230        &mut self.handles
231    }
232
233    /// Returns the fact store.
234    pub fn facts(&self) -> &BTreeFactStore {
235        &self.facts
236    }
237
238    /// Returns the fact store mutably.
239    pub fn facts_mut(&mut self) -> &mut BTreeFactStore {
240        &mut self.facts
241    }
242
243    /// Returns the effect ledger.
244    pub fn effect_ledger(&self) -> &EffectLedger {
245        &self.effect_ledger
246    }
247
248    /// Returns the effect ledger mutably.
249    pub fn effect_ledger_mut(&mut self) -> &mut EffectLedger {
250        &mut self.effect_ledger
251    }
252
253    /// Returns the active control policy.
254    pub fn control_policy(&self) -> &dyn ControlPolicy {
255        self.control_policy.as_ref()
256    }
257
258    /// Returns a shared handle to the active control policy.
259    pub fn control_policy_ref(&self) -> ControlPolicyRef {
260        self.control_policy.clone()
261    }
262
263    /// Returns the name of the active control policy.
264    pub fn control_policy_name(&self) -> &'static str {
265        self.control_policy.name()
266    }
267
268    /// Replaces the active control policy.
269    pub fn set_control_policy(&mut self, control_policy: ControlPolicyRef) {
270        self.control_policy = control_policy;
271    }
272
273    pub(crate) fn with_effect_ledger<T>(
274        &mut self,
275        f: impl FnOnce(&mut Self, &mut EffectLedger) -> Result<T>,
276    ) -> Result<T> {
277        let mut ledger = std::mem::take(&mut self.effect_ledger);
278        let result = f(self, &mut ledger);
279        self.effect_ledger = ledger;
280        result
281    }
282
283    /// Inserts a claim into the fact store, subject to capability authorization.
284    pub fn insert_fact(&mut self, claim: crate::Claim) -> Result<crate::Ref> {
285        self.facts
286            .insert_authorized(&self.capabilities, &mut self.datum_store, claim)
287    }
288
289    /// Inserts a claim and records it as part of a loaded library's receipt.
290    ///
291    /// When the claim did not already exist, `unload_lib` retracts it with the
292    /// rest of `lib_id`'s recorded load effects. Pre-existing identical claims
293    /// are left owned by their original publisher.
294    pub fn insert_fact_for_lib(
295        &mut self,
296        lib_id: LibId,
297        claim: crate::Claim,
298    ) -> Result<crate::Ref> {
299        let (reference, inserted) = self.insert_recorded_fact(claim)?;
300        if let Some(inserted) = inserted {
301            self.record_load_claims(lib_id, vec![inserted]);
302        }
303        Ok(reference)
304    }
305
306    pub(crate) fn insert_recorded_fact(
307        &mut self,
308        claim: crate::Claim,
309    ) -> Result<(crate::Ref, Option<ContentId>)> {
310        let id = claim.content_id(&mut self.datum_store)?;
311        let existed = self.facts.get(&id).is_some();
312        let inserted = self.insert_fact(claim)?;
313        let crate::Ref::Content(inserted_id) = inserted else {
314            return Err(Error::Lib(
315                "fact insertion returned a non-content reference".to_owned(),
316            ));
317        };
318        debug_assert_eq!(inserted_id, id);
319        Ok((
320            crate::Ref::Content(inserted_id.clone()),
321            (!existed).then_some(inserted_id),
322        ))
323    }
324
325    /// Queries the fact store for claims matching `pattern`, applying read policy.
326    pub fn query_facts(&self, pattern: crate::ClaimPattern) -> Result<Vec<crate::Claim>> {
327        self.facts.query_authorized(self, pattern)
328    }
329
330    pub(crate) fn record_load_claims(&mut self, lib_id: LibId, claim_ids: Vec<ContentId>) {
331        if claim_ids.is_empty() {
332            return;
333        }
334        self.load_claims
335            .entry(lib_id)
336            .or_default()
337            .extend(claim_ids);
338    }
339
340    pub(crate) fn remove_load_claims(&mut self, lib_ids: &[LibId]) {
341        for lib_id in lib_ids {
342            if let Some(claim_ids) = self.load_claims.remove(lib_id) {
343                for claim_id in claim_ids {
344                    self.facts.remove(&claim_id);
345                }
346            }
347        }
348    }
349
350    /// Returns the limits bounding number-domain promotion search.
351    pub fn promotion_search_limits(&self) -> PromotionSearchLimits {
352        self.promotion_search_limits
353    }
354
355    /// Sets the limits bounding number-domain promotion search.
356    pub fn set_promotion_search_limits(&mut self, limits: PromotionSearchLimits) {
357        self.promotion_search_limits = limits;
358    }
359
360    pub(crate) fn load_cx(&self) -> LoadCx {
361        LoadCx::new(
362            self.capabilities.clone(),
363            self.factory.clone(),
364            self.registry.clone(),
365        )
366    }
367
368    /// Returns the active evaluation policy.
369    pub fn eval_policy(&self) -> &dyn EvalPolicy {
370        self.eval_policy.as_ref()
371    }
372
373    /// Returns a shared handle to the active evaluation policy.
374    pub fn eval_policy_ref(&self) -> EvalPolicyRef {
375        self.eval_policy.clone()
376    }
377
378    /// Returns the name of the active evaluation policy.
379    pub fn eval_policy_name(&self) -> &'static str {
380        self.eval_policy.name()
381    }
382
383    /// Replaces the active evaluation policy.
384    pub fn set_eval_policy(&mut self, eval_policy: EvalPolicyRef) {
385        self.eval_policy = eval_policy;
386    }
387
388    /// Installs a macro expander.
389    pub fn set_macro_expander(&mut self, macro_expander: MacroExpanderRef) {
390        self.macro_expander = Some(macro_expander);
391    }
392
393    /// Removes any installed macro expander.
394    pub fn clear_macro_expander(&mut self) {
395        self.macro_expander = None;
396    }
397
398    /// Returns the installed macro expander, if any.
399    pub fn macro_expander_ref(&self) -> Option<MacroExpanderRef> {
400        self.macro_expander.clone()
401    }
402
403    /// Expands macros in `expr` for the given phase, or returns it unchanged.
404    pub fn expand_macros(&mut self, phase: Phase, expr: Expr) -> Result<Expr> {
405        match self.macro_expander.clone() {
406            Some(expander) => expander.expand_expr(self, phase, expr),
407            None => Ok(expr),
408        }
409    }
410
411    /// Returns the accumulated diagnostics.
412    pub fn diagnostics(&self) -> &Diagnostics {
413        &self.diagnostics
414    }
415
416    /// Drains and returns the accumulated diagnostics.
417    pub fn take_diagnostics(&mut self) -> Vec<Diagnostic> {
418        self.diagnostics.take()
419    }
420
421    /// Records an already-built diagnostic.
422    pub fn push_diagnostic(&mut self, diagnostic: Diagnostic) {
423        self.diagnostics.push_diagnostic(diagnostic);
424    }
425
426    /// Records an info-level diagnostic from a message.
427    pub fn push_info(&mut self, message: impl Into<String>) {
428        self.diagnostics.push_info(message);
429    }
430
431    /// Grants a capability to this context.
432    pub fn grant(&mut self, capability: CapabilityName) {
433        self.capabilities.insert(capability);
434    }
435
436    /// Grants a capability named by a static string.
437    pub fn grant_named(&mut self, capability: &'static str) {
438        self.capabilities.insert(CapabilityName::new(capability));
439    }
440
441    /// Returns the granted capability set.
442    pub fn capabilities(&self) -> &Capabilities {
443        &self.capabilities
444    }
445
446    /// Runs `f` with `capabilities` installed, then restores the prior set.
447    pub fn with_capabilities<T>(
448        &mut self,
449        capabilities: Capabilities,
450        f: impl FnOnce(&mut Self) -> Result<T>,
451    ) -> Result<T> {
452        let saved = std::mem::replace(&mut self.capabilities, capabilities);
453        let result = f(self);
454        self.capabilities = saved;
455        result
456    }
457
458    /// Resolves a registered class by symbol.
459    pub fn resolve_class(&self, symbol: &Symbol) -> Result<Value> {
460        self.registry()
461            .class_by_symbol(symbol)
462            .cloned()
463            .ok_or_else(|| Error::UnknownClass {
464                class: symbol.clone(),
465            })
466    }
467
468    /// Resolves a registered function by symbol.
469    pub fn resolve_function(&self, symbol: &Symbol) -> Result<Value> {
470        self.registry()
471            .function_by_symbol(symbol)
472            .cloned()
473            .ok_or_else(|| Error::UnknownFunction {
474                function: symbol.clone(),
475            })
476    }
477
478    /// Resolves a registered macro by symbol.
479    pub fn resolve_macro(&self, symbol: &Symbol) -> Result<Value> {
480        self.registry()
481            .macro_by_symbol(symbol)
482            .cloned()
483            .ok_or_else(|| Error::UnknownSymbol {
484                symbol: symbol.clone(),
485            })
486    }
487
488    /// Resolves a registered shape by symbol.
489    pub fn resolve_shape(&self, symbol: &Symbol) -> Result<Value> {
490        self.registry()
491            .shape_by_symbol(symbol)
492            .cloned()
493            .ok_or_else(|| Error::UnknownSymbol {
494                symbol: symbol.clone(),
495            })
496    }
497
498    /// Resolves a registered codec by symbol.
499    pub fn resolve_codec(&self, symbol: &Symbol) -> Result<Value> {
500        self.registry()
501            .codec_by_symbol(symbol)
502            .cloned()
503            .ok_or_else(|| Error::UnknownSymbol {
504                symbol: symbol.clone(),
505            })
506    }
507
508    /// Resolves a registered number domain by symbol.
509    pub fn resolve_number_domain(&self, symbol: &Symbol) -> Result<Value> {
510        self.registry()
511            .number_domain_by_symbol(symbol)
512            .cloned()
513            .ok_or_else(|| Error::UnknownSymbol {
514                symbol: symbol.clone(),
515            })
516    }
517
518    /// Resolves a registered value binding by symbol.
519    pub fn resolve_value(&self, symbol: &Symbol) -> Result<Value> {
520        self.registry()
521            .value_by_symbol(symbol)
522            .cloned()
523            .ok_or_else(|| Error::UnknownSymbol {
524                symbol: symbol.clone(),
525            })
526    }
527
528    /// Calls a callable value with already-evaluated arguments.
529    pub fn call_value(&mut self, value: Value, args: Args) -> Result<Value> {
530        let Some(callable) = value.object().as_callable() else {
531            return Err(Error::TypeMismatch {
532                expected: "callable",
533                found: "non-callable",
534            });
535        };
536        callable.call(self, args)
537    }
538
539    /// Calls a callable value with raw, unevaluated argument expressions.
540    pub fn call_exprs(&mut self, value: Value, args: Vec<crate::expr::Expr>) -> Result<Value> {
541        let Some(callable) = value.object().as_callable() else {
542            return Err(Error::TypeMismatch {
543                expected: "callable",
544                found: "non-callable",
545            });
546        };
547        callable.call_exprs(self, crate::object::RawArgs::new(args))
548    }
549
550    /// Resolves a function by symbol and calls it.
551    pub fn call_function(&mut self, symbol: &Symbol, args: Args) -> Result<Value> {
552        let function = self.resolve_function(symbol)?;
553        self.call_value(function, args)
554    }
555
556    /// Resolves a class by symbol and calls its constructor.
557    pub fn call_class(&mut self, symbol: &Symbol, args: Args) -> Result<Value> {
558        let class = self.resolve_class(symbol)?;
559        self.call_value(class, args)
560    }
561
562    /// Constructs an instance of `class` from read-time arguments.
563    ///
564    /// Requires the [`read_construct_capability`](crate::capability::read_construct_capability).
565    pub fn read_construct(&mut self, class: &Symbol, args: Vec<Value>) -> Result<Value> {
566        self.require(&read_construct_capability())?;
567
568        let class_value = self.resolve_class(class)?;
569        let Some(class_impl) = class_value.object().as_class() else {
570            return Err(Error::TypeMismatch {
571                expected: "class",
572                found: "non-class",
573            });
574        };
575        let Some(read_constructor) = class_impl.read_constructor(self)? else {
576            return Err(Error::Eval(format!(
577                "class {} has no read constructor",
578                class
579            )));
580        };
581        let Some(read_impl) = read_constructor.object().as_read_constructor() else {
582            return Err(Error::TypeMismatch {
583                expected: "read-constructor",
584                found: "non-read-constructor",
585            });
586        };
587        read_impl.construct_read(self, args)
588    }
589
590    /// Forces a value to the requested demand through the active eval policy.
591    pub fn force(&mut self, value: Value, demand: crate::eval::Demand) -> Result<Value> {
592        let eval_policy = self.eval_policy.clone();
593        eval_policy.force(self, value, demand)
594    }
595
596    /// Evaluates an expression through the active eval policy.
597    pub fn eval_expr(&mut self, expr: crate::expr::Expr) -> Result<Value> {
598        let eval_policy = self.eval_policy.clone();
599        eval_policy.eval_expr(self, expr)
600    }
601
602    /// Returns true when `name` resolves across environment or registry layers.
603    pub fn symbol_is_bound(&mut self, name: &Symbol) -> bool {
604        self.env().get(name).is_some()
605            || self.resolve_function(name).is_ok()
606            || self.resolve_class(name).is_ok()
607            || self.resolve_shape(name).is_ok()
608            || self.resolve_value(name).is_ok()
609    }
610
611    /// Resolves an unbound value-position symbol through the active eval policy.
612    pub fn resolve_unbound_symbol(&mut self, symbol: Symbol) -> Result<Value> {
613        let eval_policy = self.eval_policy_ref();
614        eval_policy.resolve_unbound_symbol(self, symbol)
615    }
616
617    /// Resolves an unbound call through the active eval policy.
618    pub fn resolve_unbound_call(
619        &mut self,
620        operator: Symbol,
621        args: Vec<crate::expr::Expr>,
622    ) -> Result<Value> {
623        let eval_policy = self.eval_policy_ref();
624        eval_policy.resolve_unbound_call(self, operator, args)
625    }
626
627    /// Demands a capability, returning [`Error::CapabilityDenied`] when absent.
628    pub fn require(&self, capability: &CapabilityName) -> Result<()> {
629        if self.capabilities.contains(capability) {
630            Ok(())
631        } else {
632            Err(Error::CapabilityDenied {
633                capability: capability.clone(),
634            })
635        }
636    }
637
638    /// Demands every capability in turn, failing on the first absent one.
639    pub fn require_all(&self, capabilities: &[CapabilityName]) -> Result<()> {
640        for capability in capabilities {
641            self.require(capability)?;
642        }
643        Ok(())
644    }
645}