Skip to main content

sim_lib_lang_javascript/
profile.rs

1use sim_kernel::{Cx, Expr, Result, Symbol, Value};
2use sim_lib_standard_core::{
3    CoercionPolicy, GuestRuntimeKit, LanguageProfile, OrganUse, ProfileBackingLib, ProfileRegistry,
4    TruthPolicy, install_language_profile,
5};
6use std::sync::Arc;
7
8/// One intrinsic admitted by this phase's checked scalar core.
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub struct JavascriptIntrinsic {
11    /// ECMAScript name.
12    pub name: &'static str,
13    /// Constructor, namespace, prototype, or method.
14    pub kind: &'static str,
15    /// Composed implementation boundary.
16    pub backing: &'static str,
17}
18
19/// Intrinsics admitted by the thin core; later phases extend this manifest.
20pub const fn javascript_intrinsic_manifest() -> &'static [JavascriptIntrinsic] {
21    include!(concat!(env!("OUT_DIR"), "/javascript_intrinsics.rs"))
22}
23/// Explicit unsupported surface for the current checked phase.
24pub const fn javascript_gap_catalog() -> &'static [&'static str] {
25    &[
26        "compiler-or-bytecode",
27        "foreign-engine-or-node",
28        "general-realm-agent-engine",
29        "host-event-loop",
30        "weak-apis",
31        "retain-policy-leaks-cycles",
32        "proxy-invariants",
33        "exotic-object-invariants",
34    ]
35}
36/// Build the inspectable JavaScript language profile.
37pub fn javascript_core_profile() -> LanguageProfile {
38    let mut p = LanguageProfile::new(Symbol::qualified("lang", "javascript-core/v1"))
39        .with_reader(Symbol::qualified("codec", "javascript"))
40        .with_lowering(Symbol::qualified("javascript", "expr-lowering/v1"))
41        .with_eval_policy(Symbol::qualified("javascript", "direct-eval/v1"))
42        .with_organ(OrganUse::new(sim_lib_binding::binding_organ_symbol()))
43        .with_organ(OrganUse::new(sim_lib_control::control_organ_symbol()))
44        .with_organ(OrganUse::new(sim_lib_mutation::mutation_organ_symbol()))
45        .with_organ(OrganUse::new(sim_lib_sequence::sequence_organ_symbol()))
46        .with_organ(OrganUse::new(sim_lib_pattern::pattern_organ_symbol()))
47        .with_organ(OrganUse::new(sim_lib_dispatch::dispatch_organ_symbol()))
48        .requiring(sim_lib_mutation::standard_mutate_capability());
49    for gap in javascript_gap_catalog() {
50        p = p.with_unsupported_form(Symbol::qualified("javascript", *gap));
51    }
52    p
53}
54/// Install the profile and shared backing-organ declarations.
55pub fn install_javascript_core_profile(
56    cx: &mut Cx,
57    registry: &mut ProfileRegistry,
58) -> Result<LanguageProfile> {
59    install_language_profile(
60        cx,
61        registry,
62        javascript_core_profile(),
63        &[
64            ProfileBackingLib::loadable(
65                sim_lib_binding::binding_organ_symbol(),
66                sim_lib_binding::manifest_name(),
67                sim_lib_binding::install_binding_lib,
68                Some(sim_lib_binding::publish_binding_organ_claims_for_lib),
69            ),
70            ProfileBackingLib::loadable(
71                sim_lib_control::control_organ_symbol(),
72                sim_lib_control::manifest_name(),
73                sim_lib_control::install_control_lib,
74                None,
75            ),
76            ProfileBackingLib::unresolved(
77                sim_lib_mutation::mutation_organ_symbol(),
78                Symbol::qualified("sim", "mutation"),
79            ),
80            ProfileBackingLib::loadable(
81                sim_lib_sequence::sequence_organ_symbol(),
82                sim_lib_sequence::manifest_name(),
83                sim_lib_sequence::install_sequence_lib,
84                Some(sim_lib_sequence::publish_sequence_organ_claims_for_lib),
85            ),
86            ProfileBackingLib::loadable(
87                sim_lib_pattern::pattern_organ_symbol(),
88                sim_lib_pattern::manifest_name(),
89                sim_lib_pattern::install_pattern_lib,
90                Some(sim_lib_pattern::publish_pattern_organ_claims_for_lib),
91            ),
92            ProfileBackingLib::unresolved(
93                sim_lib_dispatch::dispatch_organ_symbol(),
94                Symbol::qualified("sim", "dispatch"),
95            ),
96        ],
97        &[],
98    )
99}
100struct JsTruth;
101impl TruthPolicy for JsTruth {
102    fn is_truthy(&self, cx: &mut Cx, value: &Value) -> Result<bool> {
103        Ok(!matches!(
104            value.object().as_expr(cx)?,
105            Expr::Bool(false) | Expr::Nil
106        ))
107    }
108}
109struct JsCoercion;
110impl CoercionPolicy for JsCoercion {
111    fn to_number(&self, _: &mut Cx, _: &Value) -> Result<Option<Value>> {
112        Ok(None)
113    }
114    fn to_string(&self, _: &mut Cx, _: &Value) -> Result<Option<Value>> {
115        Ok(None)
116    }
117}
118/// Build the runtime-kit registration used by the direct evaluator.
119pub fn javascript_runtime_kit(cx: &mut Cx) -> Result<GuestRuntimeKit> {
120    Ok(GuestRuntimeKit::new(
121        Arc::new(JsTruth),
122        Arc::new(JsCoercion),
123        cx.factory().nil()?,
124    ))
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130    #[test]
131    fn registration_is_complete() {
132        let e = javascript_core_profile().checked_guest_evidence().unwrap();
133        assert_eq!(e.organs.len(), 6);
134        assert_eq!(e.capabilities.len(), 1);
135        assert_eq!(e.gaps.len(), 8);
136        let manifest = javascript_intrinsic_manifest();
137        assert_eq!(manifest.len(), 25);
138        assert!(manifest.windows(2).all(|pair| pair[0].name != pair[1].name));
139        assert!(
140            manifest
141                .iter()
142                .all(|entry| !entry.backing.is_empty() && !entry.kind.is_empty())
143        );
144    }
145}