sim_lib_lang_javascript/
profile.rs1use 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#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub struct JavascriptIntrinsic {
11 pub name: &'static str,
13 pub kind: &'static str,
15 pub backing: &'static str,
17}
18
19pub const fn javascript_intrinsic_manifest() -> &'static [JavascriptIntrinsic] {
21 include!(concat!(env!("OUT_DIR"), "/javascript_intrinsics.rs"))
22}
23pub 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}
36pub 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}
54pub 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}
118pub 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}